在C语言中,NULL是否被要求/定义为零?

50

在我的GCC测试程序中,NULL似乎是零,但维基百科说,NULL只需指向不可寻址的内存。

是否有编译器将NULL设置为非零值?我想知道if (ptr == NULL)是否比if (!ptr)更好的做法。


2
http://c-faq.com/null/machexamp.html - Nate C-K
4个回答

65

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==0ptr==0又等价于ptr==NULL);if(!ptr)也是很惯用的。

话虽如此,我通常会明确地写出if(ptr==NULL),而不是if(!ptr),以使检查指针是否为空更加清晰明了,而不是检查某个布尔值。


请注意,在C ++中,由于更严格的隐式转换规则, void * 转换不能存在,这将使使用此类 NULL 变得麻烦(每次都必须显式地将其转换为所比较的指针类型)。

7
然而,空指针中的字节不一定需要为零。 - aschepler
5
@aschepler: 我在回答中写了什么? - Matteo Italia
1
评论是在旧版本上的。很好的答案。 - aschepler
9
最重要的一点是:void *p; memset(&p, 0, sizeof p); 不会使 p 成为NULL指针。 - Simon Richter
3
@SimonRichter:这并不一定使p成为空指针。(在大多数系统上很可能会,但依赖于它可能会导致您的代码不可移植。) - Keith Thompson
显示剩余6条评论

11

从语言标准上看:

6.3.2.3 指针
...
3 值为0的整数常量表达式,或将这样的表达式强制转换为类型 void * 的常量表达式,称为空指针常量55)。如果将一个空指针常量转换为指针类型,则所得的指针称为空指针,保证与任何对象或函数的指针不相等。
...
55)宏 NULL 被定义在 <stddef.h>(和其他头文件)中作为空指针常量;参见7.17。

根据这种语言,宏 NULL 应该被评估为零值表达式(可以是未装饰的文字“0”,如 (void *) 0 这样的表达式,或最终评估为0的另一个宏或表达式)。表达式 ptr == NULL!ptr 应该是等价的。第二种形式往往是更惯用的 C 代码。

请注意,空指针值不一定是0。底层实现可能使用任何值来表示空指针。然而,在您的源代码中,零值指针表达式表示空指针。


3

在实际操作中,它们是相同的,但NULL与零是不同的。因为零意味着有一个值,而NULL意味着没有任何值。因此,从理论上讲,它们是不同的,NULL具有不同的含义,在某些情况下,这种区别应该是有用的。


2
接近了,但不是很准确。0 是 int 类型的值。NULL 是指针类型的值。(即使这也不太精确;NULL 是一个宏,它扩展为一个 null 指针常量,当转换为指针类型时会产生一个 null 指针。) - Keith Thompson

2

实际上不是这样的,!ptr 是正确的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接