通过空结构指针取消引用变量地址,无分段错误
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" 是有原因的。
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" 是有原因的。