在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'
被定义为空字符,也就是所有位都设置为零的字符。 '\0'
(像所有字符字面量一样)是一个整数常量,具有值零。 因此,'\0'
完全等同于未装饰的 0
整数常量-唯一的区别在于它传达给人类读者的意图(“我正在使用这个作为空字符。”)。
'\0'
和指针无关。但是,您可能会看到类似以下代码:
if (!*char_pointer)
检查字符指针是否指向空字符。
if (*char_pointer)
检查字符指针是否指向非空字符。
不要将其与空指针混淆。尽管它们的位表示相同,这样可以方便地进行一些交叉操作,但它们实际上并不是相同的东西。
有关更多信息,请参见comp.lang.c FAQ的问题5.3。 请参阅此pdf文件以获取C标准。查看第6.3.2.3节指针,第3段。
0xDEADBEEF
表示的空指针仍然是空指针,无论其位串长什么样子,它仍将等于 NULL
、0
、\0
和所有其他空指针常量形式。 - Johannes Schaub - litbptr == '\0'
。 - Andrew Keeton似乎有许多人误解了NULL、'\0'和0之间的区别。因此,为了说明问题并避免重复,以下是详细说明:
类型为int
、值为0的常量表达式,或者强制转换为void *
类型的该类型表达式是空指针常量,如果转换为指针,则成为空指针。 标准保证它与任何对象或函数的指针比较时不等。
NULL
是一个宏,定义为空指针常量。
\0
是用于表示空字符的构造,用于终止字符串。
空字符是一个字节,其所有位均设置为0。
0
。 - Pacerier这三个概念定义了0在不同上下文中的含义。
当你查看内存时,这三个始终是不同的:
NULL - 0x00000000 or 0x00000000'00000000 (32 vs 64 bit)
NUL - 0x00 or 0x0000 (ascii vs 2byte unicode)
'0' - 0x20
我希望这样能澄清它。sizeof('\0')
,并感到惊讶。 - caf如果在C语言中,NULL和0作为空指针常量是等价的,那我应该使用哪个? C FAQ列表中也解决了这个问题:
C程序员必须理解,在指针上下文中,
NULL
和0
是可以互换的,并且未经转换的0
是完全可以接受的。除非需要提醒指针参与其中,否则应将任何对NULL
(而不是0
)的使用视为温和的提醒。程序员不应该依赖它(无论是为了自己的理解还是为了编译器的理解)来区分指针0
和整数0
。只有在指针上下文中,
NULL
和0
才是等价的。当需要其他类型的0
时,不应使用NULL
,即使它可能起作用,因为这样做会发送错误的风格信息。(此外,ANSI允许定义NULL
为((void *) 0)
,这在非指针上下文中根本不起作用。)特别是当需要ASCII空字符(NUL
)时,不要使用NULL
。请提供自己的定义。
#define NUL '\0'
如果你确实必须这样做。
64-bit data models
Data model short int long long long pointers Sample operating systems
LLP64 16 32 32 64 64 Microsoft Win64 (X64/IA64)
LP64 16 32 64 64 64 Most Unix and Unix-like systems (Solaris, Linux, etc.)
ILP64 16 64 64 64 64 HAL
SILP64 64 64 64 64 64 ?
编辑:添加了更多关于字符字面量的内容。
#include <stdio.h>
int main(void) {
printf("%d", sizeof('\0'));
return 0;
}
'\0'
不是一个 1 字节的值。它是一个字符字面量,是一个整数常量表达式 - 因此如果可以说它有一个大小,那么它就是 int
的大小(它必须至少为 2 个字节)。如果你不相信我,请计算 sizeof('\0')
并自行查看。'\0'
、0
和 0x0
都是完全等价的。 - cafsizeof('\0')
。 - Eugene Yokota有一篇很好的文章,对于刚开始学习C语言的人很有帮助(来自Linden所写的《专家C编程》)
单个'l'空字符和双个'l'空指针
记住这个小押韵,以便正确使用指针和ASCII零:
The one "l" NUL ends an ASCII string,
The two "l" NULL points to no thing.
Apologies to Ogden Nash, but the three "l" nulll means check your spelling.
NUL
是一个控制码,例如BEL
、VT
、HT
、SOT
等,因此最多只有3个字符。 - glglgl0x00
的字节,在ASCII表中,是特殊字符NUL
或NULL
。在C语言中,由于不应该在源代码中嵌入控制字符,因此用转义的0来表示,即\0
。
但真正的NULL不是一个值,它是缺少值。对于指针而言,它意味着指针没有任何指向。在数据库中,它意味着字段中没有值(这并不意味着该字段为空白、为0或填充了空格)。
给定系统或数据库文件格式用于表示NULL
的实际值不一定是0x00
。
NULL
不能保证为0,其确切值取决于架构。大多数主要的架构将其定义为(void*)0
。
'\0'
始终等于0,因为字符字面量中的第0个字节是如何编码的。
我不记得C编译器是否需要使用ASCII - 如果不是,则'0'
可能不总是等于48。无论如何,除非您在非常晦涩的系统上工作,否则不太可能遇到使用EBCDIC等替代字符集的系统。
各种类型的大小在64位系统上会有所不同,但整数值将相同。
#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
NUL
在C标准语言或库中不存在(至少在我所知道的C++中也是如此)。空字符有时被称为NUL,但在C或C++中通常只被称为'\0'
。 - Keith Thompson