可以安全地假设
NULL
常量为零。
NULL
通常是一个零位模式。它可能是一个非零位模式,但现在很少看到。
OP混淆了至少4件事:
NULL
,
空指针常量,
空指针,将
空指针与0进行比较。 C不定义
NULL常量。
NULL
是一个扩展为实现定义的空指针常量的宏。C17dr §7.19 3
带有值0的整数常量表达式或将此类表达式强制转换为类型
void *
的表达式称为
空指针常量。 C17dr §§6.3.2.3 3
因此,
空指针常量的
类型可以是
int
,
unsigned
,
long
,...或
void *
。
当整数常量表达式
1具有值0时,
空指针常量的
值为0。作为指针,如
((void*)0)
,其值/编码未指定。它普遍具有零位模式,但未指定。
可能有许多
空指针常量。它们都相互比较相等。
注意:当它是整数且为符号时,
空指针常量的
大小可能与对象指针的大小不同。通常通过需要附加一个或两个后缀的
L
来避免此大小差异。
如果将空指针常量转换为指针类型,则生成的指针(称为
空指针)保证与任何对象或函数的指针进行比较时不相等。 C17dr §§6.3.2.3 3
将空指针转换为另一种指针类型会产生该类型的空指针。任何两个空指针应该相等。 C17dr §§6.3.2.3 4
空指针的类型是某些指针,可以是像
int *,char *
这样的对象指针,也可以是像
int (*)(int, int)
或
void *
这样的函数指针。
空指针的值未指定。虽然它通常具有零的位模式,但其值是未指定的。
所有空指针无论编码如何,都会比较为相等。
将空指针与0进行比较
if(!ptr)
相当于if(!(ptr != 0))
。当指针ptr
(一个空指针)被与0进行比较时,0将被转换为一个指针,该指针是相同类型的空指针:int *
。这两个空指针可能具有不同的位模式,但它们会被比较为相等。
那么在什么情况下不能安全地假设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*
类型的。在"When an integer ..."中,指的是第一种情况,而不是像
(int)((void*)0)
中第二种情况的强制转换或转换。
!ptr
的结果与硬件中是否将空指针表示为0无关。!
并没有被定义为这样。 - user2357112NULL
宏展开成什么并不重要 - 即使NULL
展开成0
,空指针的底层表示也不需要是 0。) - user2357112