为什么在传递给 malloc 时取消引用野指针或空指针不会导致分段错误?

Why does dereferencing a wild or null pointer when passed to malloc not lead to a segmentation fault?

这些代码片段导致了段错误:

int *i;
printf("%d\n", *i);
int *i = NULL;
printf("%d\n", *i);

而这些没有:

int *i;
i = malloc(sizeof *i);
int *i = NULL;
i = malloc(sizeof *i);

在所有示例中,野指针和空指针都被取消引用并作为参数传递给应该导致分段错误的函数。为什么使用 malloc 的示例没有按预期运行并产生分段错误?

在涉及 sizeof 的最后两种情况下,sizeof 运算符的操作数实际上并未计算。观察其类型,并在编译时计算结果。

关于 sizeof 运算符的 C standard 第 6.5.3.4p2 节指出:

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

所以实际上并没有发生指针取消引用。

此外,不能保证取消引用 NULL 指针或未初始化的指针会导致崩溃。它实际上是 undefined behavior,所以它 可能会 崩溃,也可能不会。

§ 6.5.3.4 The sizeof operator

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant

6.5.3.4 The sizeof and _Alignof operators
...
2     The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

C 2011 Online Draft

在大多数情况下 sizeof 不会评估其操作数,因此不会取消引用 - 它只关心表达式 *i 类型 ,而不是它的价值。