我昨天正在面试一个中级软件工程职位的人,他提到在C中,NULL并不总是零,并且他已经看到了C的实现,其中NULL不为零。我觉得这很可疑,但我想确定。谁知道他是对的?
(回复不会影响我对这位候选人的判断,我已将决定提交给我的经理。)
答案 0 :(得分:52)
我假设你的意思是空指针。保证比较等于0
。 1 但它不必用全零位表示。 2
另请参阅空指针上的comp.lang.c FAQ。
<小时/> <子>
答案 1 :(得分:12)
一个整数常量表达式,其值为0,或者这样的表达式强制转换为类型 void *,称为空指针常量)如果将空指针常量转换为a 指针类型,结果指针,称为空指针,保证比较不等 指向任何对象或函数的指针。
§7.17也说
[...] NULL,扩展为实现定义的空指针常量[...]
NULL指针的地址可能与0不同,而它的行为与大多数情况下的相同。
(这应该与旧的C标准相同,我现在还没有这个标准)
答案 2 :(得分:12)
空指针常量始终为0. NULL
宏可以由实现定义为裸0
,或者像(void *) 0
这样的强制转换表达式,或其他一些零值整数表达式(因此标准中的“实现定义”语言)。
空指针值可能不是0。当遇到空指针常量时,它将被转换为正确的空指针值。
答案 3 :(得分:7)
在C中,有一个且只有一个上下文,其中必须将空指针常量显式地转换为特定指针类型,以便程序正常运行。该上下文通过无类型函数参数列表传递空指针。在 modern 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 *
是通过无类型参数列表时,隐式可互换,即使它们在其他任何地方也是如此。
&#34;引擎盖&#34;,这里的问题是不只是用于空指针的位模式,但是编译器可能需要知道具体的具体类型每个参数,以便正确设置一个调用框架。 (考虑MC68000,它有单独的地址和数据寄存器;一些ABI指定要在地址寄存器中传递的指针参数,但在数据寄存器中传递整数参数。还要考虑int
和void *
不是的任何ABI现在它很少见,但C仍然明确规定void *
和char *
的大小不同。)如果有一个函数原型,编译器可以使用它,但非原型函数和可变参数不提供这样的帮助。
C ++更复杂,我觉得没有资格解释如何。
答案 4 :(得分:0)
在某些实现中,指针的大小与整数的大小不同。整数上下文中的NULL为0,但实际的二进制布局不必全为0。