为什么以下表达式不是(空指针)运行时错误?
typedef struct{
int a,b,c;
} st;
st obj={10,12,15};
st *ptr1=&obj;
st *ptr2=NULL;
printf("%d",*(int *)((char*)ptr1+(int)&ptr2->b));
因为您正在对调用未定义行为的指针执行指针算术NULL
- 而这不需要崩溃。
实际上,在 GNU C 中,&ptr2->b
在st *ptr2=NULL;
结构中生成数据成员 'b' 的字节偏移量时,这里是 4
不幸的是,取消引用空指针并不总是崩溃!有时它只是愉快地前进,访问无效内存!
您可能会看到输出值“12”。当您取消引用指针时,编译器正在做的是添加偏移量以获取成员的地址。
int
s 通常是 4 个字节长,所以如果ptr2
有一个地址,比如说 10,那么ptr2->a
也必须在地址 10,ptr2->b
必须在 14,并且ptr2->c
必须在地址 18。
因为 ptr2 是NULL
,所以要加 4 到 member b
,并且NULL
+4=4。然后你添加 4ptr1
并取消引用它,这让你ptr1
成为b
会员!
但这不是便携式的,你不应该这样做!
这是完全合法的用法,因为“获取地址”-操作符实际上意味着:“不要加载/存储变量的值,只需给我您计算出的地址即可访问它。” 它在调用实际的未定义行为之前停止访问。
这是一种典型的编程习惯,它实际上被封装在 offsetof() 宏中(在 linux 中被广泛使用),并且已经进入编译器本身以提供更有意义的错误消息。有关更多详细信息,请参阅http://en.wikipedia.org/wiki/Offsetof,尽管我不同意这篇关于声明合法性的文章。