取消引用NULL指针是否保证在C/C++中崩溃程序?

ycs*_*hao 6 c c++ null struct pointers

我遇到了这个有线代码而且没有崩溃.

#include <stdio.h>
struct s
{
    char* c;
    char* c2;
};

int main()
{
    struct s* p = NULL;
    printf("%d\n", &(p->c));
    printf("%d\n", &p->c2);
    printf("%d\n", &(*p).c2);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

0
4
4
Run Code Online (Sandbox Code Playgroud)

我有几个问题来找我,我无法回答:

  1. 在c/c ++中NULL指针总是等于0吗?

  2. 如果0恰好是变量的地址会发生什么?

  3. 输出似乎是结构成员的偏移地址.这是如何计算的.我的意思是p-> c是c的地址,它不存在,因为p == NULL.如果c的地址不存在,你怎么能通过&p-> c得到c的地址?

  4. 取消引用NULL指针是否保证在C/C++中使程序崩溃?(让我们假设在系统中)

Kei*_*son 13

不,取消引用空指针不能保证崩溃.

首先,在许多情况下,编译器能够优化解除引用操作.在您的情况下,&(p->c)名义上取消引用空指针,但您然后获取结果的地址(在选择指向结构的成员之后).据推测,编译器用数字替换整个表达式,这是结构中成员的偏移量.(无法保证空指针指向地址0,或者它将以这种方式进行优化,但它恰好在您的系统上执行.)

这是标准offsetof宏的通用实现的基础.它不能在便携式标准C或C++中实现,但实现通常使用这样的系统特定技巧 - 只要它在该系统上产生正确的结果,它就完全有效.

其次,即使您实际取消引用空指针,行为也是未定义的.这可能意味着你的程序崩溃,但就语言标准而言,它可以做任何事情.

过去有一些系统(可能还有),其中空指针指向地址0,并且系统的存储器映射被设置为使得地址0是恰好包含0值的有效存储器地址.例如,在这样的机器上,空指针就像一个指向空'\0'终止字符串的指针.当在这样的系统上工作的代码无意中依赖于这种行为时,这导致了一系列错误修复,被移植到具有更强内存保护的新系统.(我认为这可能是从基于68K的Sun 3过渡到基于SPARC的Sun 4,但我不确定.)

有关空指针的更多信息,请参阅comp.lang.c FAQ的第5节.其中大部分也适用于C++.