假设 NULL 常量为零是否安全?

Is it safe to assume that the NULL constant is zero?

Richard Reese 的 Understanding and Using C Pointers 一书说:

The null concept is an abstraction supported by the null pointer constant. This constant may or may not be a constant zero. A C programmer need not be concerned with their actual internal representation.

我的问题是,因为 "this constant may or may not be a constant zero," 在我的代码中执行如下操作是否安全:

int *ptr = NULL;
// Some code which probably sets ptr to a valid memory address

if(!ptr)
{
   ERROR();
}

如果 NULL 不为 0,则 if 子句有可能计算为真。

if(!ptr) 是检查 NULL 指针的安全方法。

表达式 !x 完全等同于 0 == x。常量 0 是一个 NULL 指针常量,任何指针都可以与 NULL 指针常量进行相等性比较。

即使空指针的表示不是 "all bits 0"。

也是如此

关于 ! 运算符的 C standard 第 6.5.3.3p5 节指出:

The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int. The expression !E is equivalent to (0==E).

关于指针转换的第 6.3.2.3p3 节指出:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

Is it safe to assume that the NULL constant is zero?

NULL 将比较等于 0.
NULL 非常 通常是零位模式。 NULL 可能是非零位模式 - 但这些天没有看到。


OP 混合了至少 4 个东西:NULL空指针常量空指针、比较 空指针 到 0。C 没有定义 NULL 常量

NULL

NULL is a macro "which expands to an implementation-defined null pointer constant" C17dr § 7.19 3

空指针常量

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. C17dr § § 6.3.2.3 3

因此空指针常量类型可能是intunsignedlong, ... 或 void * .

当整数常量表达式1时,空指针常量为0。作为像((void *)0)这样的指针,它的value/encoding是没有规定的。它普遍存在零的位模式,但没有指定。

可能有很多空指针常量。他们都比较相等。

注:空指针常量大小,当为整数时,可能与对象指针的大小不同.通常通过根据需要附加一个 L 或两个后缀来避免这种大小差异。

空指针

If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function. C17dr § § 6.3.2.3 3

Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal. C17dr § § 6.3.2.3 4

空指针的类型是一些指针,可以是像int *, char *这样的对象指针,也可以是像int (*)(int, int)void *这样的函数指针。

未指定空指针。它普遍存在零的位模式,但没有指定。

所有 空指针 都比较相等,无论它们的编码如何。

比较一个空指针和0

if(!ptr) 等同于 if(!(ptr != 0))。当指针ptr,即空指针,与0进行比较时,零被转换为指针,空指针 ] 同类型:int *。这2个空指针可能有不同的位模式,比较相等。


那么什么时候假设 NULL 常量为零是不安全的呢?

NULL 可能是 ((void*)0) 并且它的位模式可能不同于零。无论其编码如何,它确实像上面那样比较等于 0。已经讨论过调用指针比较,而不是整数比较。将 NULL 转换为整数可能不会导致整数值 0,即使 ((void*)0) 全部为零位也是如此。

printf("%ju\n", (uintmax_t)(uintptr_t)NULL); // Possible not 0

注意这是将指针转换为整数,而不是 if(!ptr) 的情况,其中 0 被转换为指针。

C 规范包含许多旧的做事方式,并且对新颖的新方式持开放态度。我从来没有遇到过 NULL 不是全零位模式的实现。鉴于存在许多假设 NULL 都是零位的代码,我怀疑只有旧的模糊实现使用过非零位模式 NULL 并且 NULL 几乎可以肯定是全零位模式。


1 空指针常量 是 1) 整数或 2) 一个 void*。 “当一个整数......”指的是第一种情况,而不是第二种情况的强制转换或转换,如 (int)((void*)0).

chux 写了一个很好的、详细的答案,但具体到那本书,我会怀疑它的质量:

  • This constant may or may not be a constant zero

    这是错误的,它必须始终为零或零转换为 void*。空指针常量的定义见C17 6.3.2.3/3:

    An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

    这意味着所有整数常量表达式如00L0u0x0'[=15=]'等都是空指针常量。如果其中任何一个被强制转换为 void*,它也是一个空指针常量。

  • A C programmer need not be concerned with their actual internal representation.

    作者显然混淆了空指针常量空指针这两个正式术语。程序员不需要关心空指针的内部表示。他们确实需要知道是什么使有效的空指针成为常量。最安全、最易读的方法是使用 NULL 宏,它保证是一个空指针常量。

所以关于你的问题 "is it safe for me to do things like the below in my code" - 是的,!ptr 检查空指针是完全安全的,即使 ptr==NULL 是更易读的代码。