简体   繁体   English

在 C 中 NULL 总是零吗?

[英]Is NULL always zero in C?

I was interviewing a guy for a mid-level software engineering position yesterday, and he mentioned that in C, NULL is not always zero and that he had seen implementations of C where NULL is not zero.昨天我面试了一个中级软件工程职位的人,他提到在 C 中,NULL 并不总是零,而且他见过 C 的实现,其中 NULL 不为零。 I find this highly suspect, but I want to be sure.我觉得这很可疑,但我想确定一下。 Anyone know if he is right?有谁知道他说得对吗?

(Responses will not affect my judgement on this candidate, I've already submitted my decision to my manager.) (回复不会影响我对这个候选人的判断,我已经向我的经理提交了我的决定。)

I'm assuming you mean the null pointer.我假设你的意思是空指针。 It is guaranteed to compare equal to 0 .保证比较等于0 1 But it doesn't have to be represented with all-zero bits. 1但它不必用全零位表示。 2 2

See also the comp.lang.c FAQ on null pointers.另请参阅有关空指针的comp.lang.c 常见问题解答


  1. See C99, 6.3.2.3.见 C99,6.3.2.3。
  2. There's no explicit claim;没有明确的要求; but see the footnote for C99, 7.20.3 (thanks to @birryree in the comments).但请参阅 C99 的脚注 7.20.3(感谢评论中的 @birryree)。

§ 6.3.2.3 of the C99 standard says C99 标准的第 6.3.2.3 节说

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.值为 0 的整数常量表达式,或这种转换为 void * 类型的表达式,称为空指针常量)如果将空指针常量转换为指针类型,则结果指针(称为空指针)保证为比较不等于指向任何对象或函数的指针。

§ 7.17 also says § 7.17 还说

[...] NULL which expands to an implementation-defined null pointer constant [...] [...] NULL 扩展为实现定义的空指针常量 [...]

The address of the NULL pointer might be different from 0, while it will behave like it was in most cases. NULL 指针的地址可能与 0 不同,但在大多数情况下它将表现得像它一样。

(This should be the same as in older C standards, which I don't have at hand right now) (这应该与旧的 C 标准相同,我现在手头没有)

The null pointer constant is always 0. The NULL macro may be defined by the implementation as a naked 0 , or a cast expression like (void *) 0 , or some other zero-valued integer expression (hence the "implementation defined" language in the standard).空指针常量始终为 0。 NULL宏可以由实现定义为裸0 ,或者像(void *) 0这样的强制转换表达式,或者其他一些零值整数表达式(因此在标准)。

The null pointer value may be something other than 0. When a null pointer constant is encountered, it will be converted to the proper null pointer value.空指针可能不是 0。当遇到空指针常量时,它将被转换为正确的空指针值。

In C, there is one, and only one, context where it is necessary to explicitly cast a null pointer constant to a specific pointer type in order for the program to operate correctly.在 C 语言中,只有一个上下文需要显式地将空指针常量转换为特定的指针类型,以便程序正确运行。 That context is passing a null pointer through an untyped function argument list.该上下文通过无类型函数参数列表传递空指针。 In modern C, this only happens when you need to pass a null pointer to a function that takes a variable number of arguments.现代C 中,这仅在您需要将空指针传递给采用可变数量参数的函数时才会发生。 (In legacy C, it happens with any function not declared with a prototype.) The paradigmatic example is execl , where the very last argument must be a null pointer explicitly cast to (char *) : (在遗留 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

Yes, that last example has undefined behavior even if NULL is defined as ((void *)0) , because void * and char * are not implicitly interconvertible when passed through an untyped argument list, even though they are everywhere else.是的,即使将NULL定义为((void *)0) ,最后一个示例也具有未定义的行为,因为void *char *在通过无类型参数列表时不能隐式地相互转换,即使它们在其他任何地方也是如此。 (There is language in C2011 that makes them implicitly interconvertible when passed through va_arg , but they forgot to specify that implementation-provided library functions access variadic arguments as-if by calling va_arg , so you can only rely on that for variadic functions that are part of your program. Someone should probably file a DR.) (C2011 中有一种语言使它们在通过va_arg传递时可以隐式地相互转换,但是他们忘记指定实现提供的库函数就像通过调用va_arg一样访问可变参数参数,因此您只能依赖它来处理属于部分的可变参数函数你的程序。有人可能应该提交一份 DR。)

"Under the hood", the problem here is not just with the bit pattern used for a null pointer, but that the compiler may need to know the exact concrete type of each argument in order to set up a call frame correctly. “引擎盖下”,这里的问题只是用于空指针的位模式,但编译器可能需要知道每个参数的精确具体类型,以便正确地建立呼叫帧。 (Consider the MC68000, with its separate address and data registers; some ABIs specified pointer arguments to be passed in address registers but integer arguments in data registers. Consider also any ABI where int and void * are not the same size. And it's vanishingly rare nowadays, but C does still explicitly provide for void * and char * not being the same size. [EDIT: I'm not sure, but this may no longer be permitted.]) If there's a function prototype, the compiler can use that, but unprototyped functions and variadic arguments offer no such assistance. (考虑 MC68000,它具有单独的地址和数据寄存器;一些 ABI 指定要在地址寄存器中传递的指针参数,但在数据寄存器中指定整数参数。还要考虑intvoid *大小不同的任何 ABI。而且这种情况非常罕见现在,但 C 仍然明确规定void *char *的大小不同。 [编辑:我不确定,但这可能不再被允许。]) 如果有函数原型,编译器可以使用它,但非原型函数和可变参数没有提供这样的帮助。

C++ is more complicated and I don't feel qualified to explain how. C++ 更复杂,我觉得没有资格解释如何。

On some implementations, size of pointer is not the same as the size of integer.在某些实现中,指针的大小与整数的大小不同。 NULL in integer context is 0, but the actual binary layout does not have to be all 0s.整数上下文中的 NULL 为 0,但实际的二进制布局不必全为 0。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM