通过空结构指针取消引用变量地址,无分段错误

dereference variable address through null structure pointer, no segmentation fault

typedef struct {
    int a;
}stTemp_t;

int main()
{
stTemp_t *pstTemp = NULL;
int *p = &(pstTemp->a);       // <<----- supposedly de-ref NULL pointer

return 0;
}

上面指出的指令,我认为应该会导致分段错误,但实际上并没有。我尝试使用 "gcc -O0" 省略默认的编译器优化。

很自然地,如果我用 int i = pstTemp->a 替换它,我会得到一个段错误。我试图通过 gdb 运行 上面的程序来弄清楚发生了什么,下面是我的观察 -

(gdb) p pstTemp
 = (stTemp_t *) 0x0
(gdb) p pstTemp->a
Cannot access memory at address 0x0
(gdb) p &(pstTemp->a)
 = (int *) 0x0

</code> 中,我们可以看到当我尝试打印 <code>&(pstTemp->a) 时,它似乎被解释为一个地址,因此相当于 int *p = NULL.

但是我的疑问是,语句 (pstTemp->a) 不应该在 & 生效之前被评估并导致段错误吗?

这是未定义的行为。

这里并没有崩溃,因为没有实际的解引用,我们只取了(pstTemp->b)地址,其实就是[=14]的偏移量=] 字段(很可能是 4,取决于 int 的大小和编译器)。

试试这个:

typedef struct {
    int a;
    int b;
} stTemp_t;

int main()
{
  stTemp_t *pstTemp = NULL;
  int *p = &(pstTemp->b);

  printf ("%p", p);
  return 0;
}

输出很可能是:

00000004

但是

   printf ("%d", pstTemp->b);

很可能会崩溃。

实际上,甚至 取消引用 空指针的行为导致您的代码中出现未定义的行为。

当寻址 (&) 和取消引用 (*->) 操作紧随其后时,它们会相互抵消并折叠成 指针运算。 因此,表达式 &pstTemp->a 产生 a.

的地址

但是,对 NULL 指针执行指针运算是未定义的行为。由于没有完成实际的取消引用(并且行为无论如何都是未定义的),似乎编译器只是没有发出任何可能导致分段错误的明显有害的代码。

不要指望未定义的行为会导致任何特定错误。它被称为 undefined 而不是 "guaranteed crash" 是有原因的。