在我的GCC测试程序中,NULL
似乎是零,但维基百科说,NULL
只需指向不可寻址的内存。
是否有编译器将NULL
设置为非零值?我想知道if (ptr == NULL)
是否比if (!ptr)
更好的做法。
NULL
被保证为零,可能会转换为(void *)
1。
C99,§6.3.2.3,¶3
值为
0
的整数常量表达式,或将这样的表达式强制转换为类型void *
的表达式称为空指针常量。(55)如果将空指针常量转换为指针类型,则所得到的指针称为空指针,并保证与任何对象或函数的指针不相等。
注意55号注释如下:
55) 在
<stddef.h>
(和其他头文件)中定义了宏NULL作为空指针常量。
请注意,由于空指针规则的制定方式,您用于分配/比较空指针的值保证为零,但实际存储在指针内部的位模式可以是任何其他内容(但据我所知,只有极少数非常晦涩的平台利用了这一点,而且这应该不是一个问题,因为要“查看”底层位模式,您必须进入UB领域)。
因此,就标准而言,这两种形式是等价的(由于§6.5.3.3 ¶5,!ptr
等价于ptr==0
,ptr==0
又等价于ptr==NULL
);if(!ptr)
也是很惯用的。
话虽如此,我通常会明确地写出if(ptr==NULL)
,而不是if(!ptr)
,以使检查指针是否为空更加清晰明了,而不是检查某个布尔值。
void *
转换不能存在,这将使使用此类 NULL
变得麻烦(每次都必须显式地将其转换为所比较的指针类型)。void *p; memset(&p, 0, sizeof p);
不会使 p
成为NULL指针。 - Simon Richterp
成为空指针。(在大多数系统上很可能会,但依赖于它可能会导致您的代码不可移植。) - Keith Thompson从语言标准上看:
6.3.2.3 指针
...
3 值为0的整数常量表达式,或将这样的表达式强制转换为类型void *
的常量表达式,称为空指针常量55)。如果将一个空指针常量转换为指针类型,则所得的指针称为空指针,保证与任何对象或函数的指针不相等。
...
55)宏NULL
被定义在<stddef.h>
(和其他头文件)中作为空指针常量;参见7.17。
根据这种语言,宏 NULL 应该被评估为零值表达式(可以是未装饰的文字“0
”,如 (void *) 0
这样的表达式,或最终评估为0的另一个宏或表达式)。表达式 ptr == NULL
和 !ptr
应该是等价的。第二种形式往往是更惯用的 C 代码。
请注意,空指针值不一定是0。底层实现可能使用任何值来表示空指针。然而,在您的源代码中,零值指针表达式表示空指针。
在实际操作中,它们是相同的,但NULL与零是不同的。因为零意味着有一个值,而NULL意味着没有任何值。因此,从理论上讲,它们是不同的,NULL具有不同的含义,在某些情况下,这种区别应该是有用的。
NULL
是一个宏,它扩展为一个 null 指针常量,当转换为指针类型时会产生一个 null 指针。) - Keith Thompson实际上不是这样的,!ptr 是正确的。