在C中NULL是否总是为零?

我昨天正在采访一个中级软件工程职位的人,他提到,在C中,NULL并不总是零,而且他看到了C的实现,其中NULL不为零。 我觉得这非常可疑,但我想确定。 任何人都知道他是对的吗?

(回答不会影响我对这个候选人的判断,我已经把我的决定提交给我的经理。)

我假设你的意思是空指针。 保证比较等于01但它不一定要用全零位表示。 2

另请参阅关于空指针的comp.lang.c常见问题解答 。


  1. 见C99,6.3.2.3。
  2. 没有明确的说法; 但请参阅C99的脚注7.20.3(感谢@birryree的评论)。

C99标准的第6.3.2.3节说

一个整数常量expression式的值为0,或者这样的一个expression式转换为void *types,被称为空指针常量)如果空指针常量被转换为指针types,则所产生的称为空指针的指针被保证比较不等于指向任何对象或函数的指针。

§7.17也说

NULL扩展为实现定义的空指针常量[…]

NULL指针的地址可能不是0,而它的行为就像在大多数情况下一样。

(这应该和旧的C标准一样,我现在手边没有)

空指针常量总是0. NULLmacros可以由实现定义为裸0 ,或者像(void *) 0这样的强制转换expression式,或者其他一些零值整数expression式(因此是“实现定义的”标准)。

空指针可能不是0.当遇到空指针常量时,它将被转换为正确的空指针值。

在C中,只有一个上下文需要显式地将空指针常量转换为特定的指针types,以便程序正常运行。 该上下文传递一个空指针通过一个无types的函数参数列表。 在现代 C语言中,只有当你需要传递一个空指针给一个带有可变数目参数的函数时才会发生这种情况。 (在传统的C语言中,任何没有用原型声明的函数都会发生这种情况)典型的例子是execl ,其中最后一个参数必须是明确地转换为(char *)的空指针:

 execl("/bin/ls", "ls", "-l", (char *)0); // correct execl("/bin/ls", "ls", "-l", (char *)NULL); // correct, but unnecessarily verbose execl("/bin/ls", "ls", "-l", 0); // undefined behavior execl("/bin/ls", "ls", "-l", NULL); // ALSO undefined behavior 

是的, 即使 NULL定义为((void *)0) ,最后一个示例也有未定义的行为,因为void *char *在通过非types化参数列表传递时不是隐式互换,即使它们在其他地方。

在“引擎盖下”,这里的问题不仅仅是用于空指针的位模式,而且编译器可能需要知道每个参数的确切具体types,以便正确地build立一个调用框架。 (考虑MC68000,带有单独的地址和数据寄存器;一些ABI指定的指针参数要在地址寄存器中传递,但是在数据寄存器中是整数参数,还要考虑任何ABI,其中intvoid *的大小是不一样的。但是C仍然明确地规定void *char *不是相同的大小)。如果有函数原型,编译器可以使用它,但是未原型函数和可变参数不提供这种帮助。

C ++更复杂,我不觉得如何解释。

他是对的,在一些实现中,指针的大小与整数的大小不一样。 整数上下文中的NULL是0,但实际的二进制布局不一定都是0。