在C语言中,不同的零值之间似乎存在差异 - NULL
,NUL
和0
。
我知道ASCII字符'0'
评估为48
或0x30
。
`NULL'指针通常被定义为。
#define NULL 0
或
#define NULL (void *)0
此外,还有一个NUL'字符
'\0',似乎也会评估为
0'。
是否存在这三个值不能相等的情况?
在64位系统上也是这样吗?
注意:本答案适用于C语言,而不是C++。
整数常数0
根据使用环境的不同,有不同的含义。在所有情况下,它仍然是一个数值为0的整数常数,只是描述的方式不同而已。
如果一个指针与常数字面0
进行比较,那么这是一个检查,看看这个指针是否是一个空指针。这个0
就被称为空指针常数。C标准定义了0
投向void *
类型,既是一个空指针也是一个空指针常量。
此外,为了帮助阅读,在头文件stddef.h
中提供了宏NULL
。根据你的编译器,也许可以#undef NULL
并重新定义为一些古怪的东西。
因此,这里有一些有效的方法来检查空指针。
if (pointer == NULL)
NULL
被定义为与空指针比较相等。 只要是有效的空指针常量,`NULL'的实际定义是什么,都是执行定义。
if (pointer == 0)
0
是空指针常数的另一种表示方法。
if (!pointer)
这个 "if "语句隐含地检查了"不是0",所以我们把它倒过来,表示"是0"。
以下是检查空指针的不正确的方法。
int mynull = 0;
<some code>
if (pointer == mynull)
对于编译器来说,这不是对空指针的检查,而是对两个变量的平等检查。如果mynull在代码中从未发生变化,并且编译器优化常数将0折叠到if语句中,这*可能会起作用,但这并不能保证,根据C标准,编译器必须产生至少一条诊断信息(警告或错误)。
请注意,在C语言中什么是空指针。这在底层架构上并不重要。如果底层架构有一个定义为地址0xDEADBEEF的空指针值,那么就要由编译器来整理这个混乱的问题了。
因此,即使在这个有趣的架构上,下面的方法仍然是检查空指针的有效方法。
if (!pointer)
if (pointer == NULL)
if (pointer == 0)
以下是检查空指针的不正确方法。
#define MYNULL (void *) 0xDEADBEEF
if (pointer == MYNULL)
if (pointer == 0xDEADBEEF)
因为这些被编译器看作是正常的比较。
'\0'
被定义为一个空字符--即一个所有位都设置为零的字符。这与指针没有关系。然而,你可能会看到与此代码类似的东西。
if (!*string_pointer)
检查字符串指针是否指向一个空字符
if (*string_pointer)
检查字符串指针是否指向一个非空字符
不要把这些与空指针混淆起来。只是因为位的表示方法是一样的,而且这允许一些方便的交叉情况,它们并不是真正的同一回事。
此外,'\0'
是(像所有字符字头一样)一个整数常数,在这种情况下,值为0。 因此,'0'
完全等同于一个未经修饰的0
整数常数--唯一的区别在于它向人类读者传达的*意图("我把它当作一个空字符。")。
参见comp.lang.c FAQ的问题5.3,了解更多信息。 参见本pdf中的C标准。查看第6.3.2.3节指针,第3段。
`NULL'不保证是0 -- 它的确切值取决于架构。大多数主要的体系结构将其定义为"(void*)0"。
'\0'
将永远等于0,因为这就是字节0在字符字面中的编码方式。
我不记得C语言编译器是否需要使用ASCII码 -- 如果不需要,'0'
可能不总是等于48。无论如何,你不太可能遇到使用EBCDIC等替代字符集的系统,除非你在**晦涩的系统上工作。
各种类型的大小在64位系统上会有所不同,但整数值是相同的。
一些评论者对NULL等于0,但不*是0表示怀疑。下面是一个示例程序,以及在这种系统上的预期输出。
#include <stdio.h>
int main () {
size_t ii;
int *ptr = NULL;
unsigned long *null_value = (unsigned long *)&ptr;
if (NULL == 0) {
printf ("NULL == 0\n"); }
printf ("NULL = 0x");
for (ii = 0; ii < sizeof (ptr); ii++) {
printf ("%02X", null_value[ii]); }
printf ("\n");
return 0;
}
该程序可以打印。
NULL == 0
NULL = 0x00000001