typedef struct {
int a;
}stTemp_t;
int main()
{
stTemp_t *pstTemp = NULL;
int *p = &(pstTemp->a); // <<----- supposedly de-ref NULL pointer
return 0;
}
上面指出的指令,我认为应该引起分割错误,但它没有。我尝试通过使用"gcc - 0"来省略默认的编译器优化。
很自然,如果我用int i = pstTemp->a
代替它,我得到一个隔离故障。我试图通过gdb运行上述程序,以弄清楚发生了什么。以下是我的观察-
(gdb) p pstTemp
$2 = (stTemp_t *) 0x0
(gdb) p pstTemp->a
Cannot access memory at address 0x0
(gdb) p &(pstTemp->a)
$3 = (int *) 0x0
在$3
中,我们可以看到,当我试图打印&(pstTemp->a)
时,它似乎被解释为一个地址,因此相当于int *p = NULL
。
然而,我的疑问是,语句(pstTemp->a)
不应该在&生效&造成隔离故障?
实际上,甚至不是解引用空指针的行为导致了代码中的未定义行为。
当一个取址操作(&
)和一个解引用操作(*
或->
)紧接在一起时,它们会相互抵消并分解成指针运算。因此,表达式&pstTemp->a
产生a
的地址。
然而,在NULL指针上执行指针算术是未定义的行为。由于没有实际的解引用(并且行为是未定义的),因此编译器似乎没有发出任何明显有害的代码,从而导致分段错误。
不要期望未定义的行为会导致任何特定的错误。它被称为undefined而不是"保证崩溃"是有原因的
这是未定义的行为。
这里不会崩溃,因为没有实际的解引用,我们只取(pstTemp->b)
的地址,这实际上是b
字段的偏移量(最有可能是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);
很可能崩溃