[英]Accessing structure elements using pointers
当下面的程序没有崩溃时,我感到很惊讶。
typedef struct _x {
int a;
char b;
int c;
} x;
main() {
x *ptr = 0;
char *d = &ptr->b;
}
根据我的理解, ->
运算符优先于&
运算符。 所以当我们尝试取消引用NULL指针tr
时,我希望程序在下面的语句中崩溃。
char *d = &ptr->b;
但语句&ptr->b
计算为有效地址。 有人可以解释一下我错了吗?
你的期望是没有根据的。 取消引用空指针时,C程序不一定“崩溃”。 当您尝试执行类似的操作时,C程序会出现所谓的未定义行为 。 未定义的行为可以通过许多不同的方式表现出来。 它可能导致崩溃。 或者它可以产生甚至类似于“工作”程序的东西。 后者显然是你的情况。
但无论如何,你的程序的行为是不确定的。 不,它不会产生一个“有效地址”,因为你似乎错误地相信。 对应于内存中没有对象存在的位置的数字地址无效(当然,空指针值除外)。
您的代码没有崩溃的原因是您实际上没有取消引用指针。 注意表达式
&ptr->b
实际上并没有尝试加载ptr
或ptr->b
的内容。 相反,它只是存储它在内存中的位置。 你最终得到的是指向ptr
指向的对象的b
字段的指针。 这将是地址0之后的几个字节,因此取消引用刚创建的指针将导致段错误。
&ptr->b == sizeof(int)
,表示_x.a
(类型为int
)之后_x
内的b
相对于地址*((x*)0)
的偏移量。 偏移量为4
(典型值为32位架构)保存在d
指针中。 您必须访问d
才能获得seg-fault。
计算地址不需要访问内存。 &ptr->b
表示“给我ptr
指向的结构的b
字段的地址。” 这样做不需要查看可能存储在该存储器位置的任何内容。
考虑索引数组而不是结构可能会有所帮助。 C将ptr[5]
定义为等价于*(ptr + 5)
,这意味着&(ptr[5])
与&(*(ptr + 5))
。 现在很容易看到&
和*
“取消”并留下(ptr + 5)
,它只涉及指针增量,而不是来自内存的负载。
C使它略微混浊,因为它区分左值和右值。 也就是说,表达式的表达式在表达式的左侧与右侧的表达式区别对待。 给出像x = y;
的陈述x = y;
,C编译器将从y
的地址加载一个值,并将其存储在x
的地址中。 这是区别: y
被隐式解除引用,但x
不是。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.