代码逐段拆解
NULL
在 C 语言中,NULL 通常被定义为 ((void *)0) 或数字 0,代表内存中的空地址(0x00000000)。
(struct A *)NULL
这里进行了一次强类型转换,告诉编译器:"假设内存地址 0 处放置着一个 struct A 类型的结构体实例"。
((struct A *)NULL)->m_float
通过指针访问运算符 -> 指向该虚构结构体中的 m_float 成员。
&(...)
最关键的一步! 在前面加上取地址符 &。
如果结构体的首地址是 0,那么成员 m_float 的地址就是:0 + m_float 的偏移量。
取出的地址值在数值上就完全等于 m_float 在结构体中的字节偏移量。
printf("%p\n", ...)
以指针(16进制)格式打印出这个计算得到的"地址"(即偏移量)。
二、 为什么不会发生"空指针崩溃"(Segmentation Fault)?
很多初学者看到 (struct A *)NULL-> 就会担心:解引用空指针不是会导致程序崩溃吗?
答案是:绝对不会崩溃!
原因:因为外面紧包裹着取地址符 &。
在编译器眼里,&(ptr->member) 这套组合拳会被直接优化/翻译为地址加法计算:
成员地址
结构体基地址
成员偏移量
成员地址=结构体基地址+成员偏移量
编译器在编译阶段就通过结构体声明算好了 m_float 的相对偏移量,它根本不会产生任何去内存中读取数据的 CPU 指令(如 MOV),因此完全不会触发非法内存读取异常。