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

the*_*ian 7 c null pointers null-pointer

Richard Reese所著的《理解和使用 C 指针》一书说:

空概念是空指针常量支持的抽象。这个常数可能是也可能不是一个常数零。AC 程序员不需要关心他们实际的内部表示。

我的问题是,由于“这个常数可能是也可能不是常数零”,我在我的代码中执行以下操作是否安全:

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

if(!ptr)
{
   ERROR();
}
Run Code Online (Sandbox Code Playgroud)

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

chu*_*ica 6

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

NULL将比较等于0
NULL非常常见的零位模式。有可能NULL是非零位模式 - 但现在还没有看到。


OP 混合了至少 4 件事:NULL空指针常量空指针、将空指针与 0进行比较。C 没有定义NULL 常量

NULL

NULL 是一个宏“它扩展为实现定义的空指针常量”C17dr § 7.19 3

空指针常量

值为 0 的整数常量表达式,或这种类型转换为void*的表达式,称为空指针常量。C17dr § 6.3.2.3 3

因此,该类型A的空指针常数可以是intunsignedlong,...或void *

当整数常量表达式为1 时空指针常量 值为0。作为像 的指针((void *)0),其值/编码未指定。它无处不在地具有零的位模式,但并未如此指定。

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

注:尺寸a的空指针常量,当它是一个整数,可从一个对象的指针的大小不同。通常通过L根据需要附加一个或两个后缀来避免这种大小差异。

空指针

如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证与指向任何对象或函数的指针不相等。C17dr § 6.3.2.3 3

将空指针转换为另一种指针类型会产生该类型的空指针。任何两个空指针比较相等。C17dr § 6.3.2.3 4

空指针的类型是一些指针,要么是对象指针之类的,要么是int *, char *函数指针之类的int (*)(int, int)void *

a的空指针没有被指定。它无处不在地具有零的位模式,但并未如此指定。

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

空指针与 0进行比较

if(!ptr)与 相同if(!(ptr != 0))。当ptr作为空指针的指针与 0 进行比较时,零将转换为指针,即相同类型的空指针int *。这2个空指针,它可以有不同的位模式,比较结果为相等。


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

NULL可能是 a((void*)0)并且它的位模式可能不同于零。无论其编码如何,它确实比较等于 0 如上所述。回想指针比较已经讨论过,而不是整数比较。转换NULL为整数可能不会导致整数值为 0,即使((void*)0)所有位都为零。

printf("%ju\n", (uintmax_t)(uintptr_t)NULL); // Possible not 0
Run Code Online (Sandbox Code Playgroud)

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

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


1空指针常数为1)的整数或2) void*。“当一个整数......”指的是第一种情况,而不是像(int)((void*)0).