1. 为什么访问非法内存不会出错?
这个问题源于一个常见的C语言宏定义:
#define GET_MEMBER_SIZE(type, member) sizeof(((type*)0)->member)
乍一看,这个宏似乎是在访问地址0处的内存,这显然是非法的。但实际上,这段代码完全合法且安全。关键在于理解sizeof操作符的特殊行为。
重要提示:sizeof是编译时操作符,不会真正执行其参数表达式中的内存访问。
2. sizeof的编译时特性解析
2.1 sizeof的工作原理
sizeof操作符在C语言中有以下关键特性:
- 它是编译时操作符,不会生成实际访问内存的机器指令
- 它只关心类型信息,不关心具体值
- 编译器会静态计算类型大小,结果作为常量嵌入代码
当编译器看到sizeof(((type*)0)->member)时:
- 解析(type*)0:将0强制转换为type指针类型
- 解析->member:确定member成员的偏移量和类型
- 计算member成员的大小
- 用计算结果替换整个sizeof表达式
2.2 编译器如何处理这个宏
让我们看一个具体例子:
struct example {
char a;
int b;
double c;
};
size_t size = GET_MEMBER_SIZE(struct example, c);
编译过程:
- 预处理阶段将宏展开为:sizeof(((struct example*)0)->c)
- 编译器分析这个表达式,确定c的类型是double
- 计算double的大小(通常是8字节)
- 生成等同于size_t size = 8;的代码
3. 深入理解地址0的使用
3.1 为什么选择地址0
使用0地址作为基址有几个优势:
- 数值简单,易于识别
- 偏移量计算直观
- 任何非零地址都可能与真实内存冲突
但实际上,任何地址值都可以:
#define GET_MEMBER_SIZE_ALT(type, member) sizeof(((type*)100)->member)

1093

被折叠的 条评论
为什么被折叠?



