NULL、'\0' 和 0 有什么区别?

What is the difference between NULL, '\0' and 0?

提问人:gnavi 提问时间:8/19/2009 最后编辑:John Kugelmangnavi 更新时间:2/23/2021 访问量:404815

问:

在 C 中,零 -- , 和 的各种值之间似乎存在差异。NULLNUL0

我知道 ASCII 字符的计算结果为 或 。'0'480x30

指针通常定义为:NULL

#define NULL 0

#define NULL (void *)0

另外,似乎也有评价的性格。NUL'\0'0

有没有这三个值不能相等的时候?

在 64 位系统上也是如此吗?

c 指针 null

评论

2赞 David Rodríguez - dribeas 8/19/2009
有关 0 和 NULL 之间差异的详细信息,请参阅 stackoverflow.com/questions/176989/...
14赞 Keith Thompson 7/9/2013
标识符在 C 标准语言或库中不存在(据我所知,在 C++ 中)。空字符有时称为 NUL,但它是 C 或 C++,通常简称为 .NUL'\0'

答:

425赞 14 revs, 8 users 49%Andrew Keeton #1

注意:这个答案适用于 C 语言,而不是 C++。


Null 指针

整数常量文本具有不同的含义,具体取决于使用它的上下文。在所有情况下,它仍然是一个具有值的整数常数,只是以不同的方式描述。00

如果将指针与常量文本进行比较,则这是检查指针是否为空指针的检查。然后,这称为 null 指针常量。C 标准定义强制转换为类型既是空指针又是空指针常量。000void *

此外,为了提高可读性,头文件中提供了宏。根据您的编译器,可能会将其重新定义为古怪的东西。NULLstddef.h#undef NULL

因此,以下是检查空指针的一些有效方法:

if (pointer == NULL)

NULL定义为等于 null 指针的比较。它是实现定义的,实际定义是什么,只要它是一个有效的空指针常量。NULL

if (pointer == 0)

0是 null 指针常量的另一种表示形式。

if (!pointer)

此语句隐式检查“is not 0”,因此我们将其反转为表示“is 0”。if

以下是检查空指针的 INVALID 方法:

int mynull = 0;
<some code>
if (pointer == mynull)

对于编译器来说,这不是对空指针的检查,而是对两个变量的相等性检查。如果代码中的 mynull 从未更改,并且编译器优化常量将 0 折叠到 if 语句中,这可能会起作用,但这并不能保证,编译器必须根据 C 标准生成至少一条诊断消息(警告或错误)。

请注意,C 语言中 null 指针的值在底层体系结构上无关紧要。如果底层架构有一个定义为地址0xDEADBEEF的空指针值,那么就由编译器来解决这个问题。

因此,即使在这个有趣的体系结构上,以下方法仍然是检查空指针的有效方法:

if (!pointer)
if (pointer == NULL)
if (pointer == 0)

以下是检查空指针的 INVALID 方法:

#define MYNULL (void *) 0xDEADBEEF
if (pointer == MYNULL)
if (pointer == 0xDEADBEEF)

因为这些被编译器视为正常比较。

空字符

'\0'定义为空字符 - 即所有位都设置为零的字符。 (与所有字符文字一样)是一个整数常量,在本例中为零值。所以完全等同于一个未经修饰的整数常量 - 唯一的区别在于它传达给人类读者的意图(“我将其用作空字符。'\0''\0'0

'\0'与指针无关。但是,您可能会看到与此代码类似的内容:

if (!*char_pointer)

检查 char 指针是否指向 null 字符。

if (*char_pointer)

检查 char 指针是否指向非 null 字符。

不要将这些与空指针混淆。仅仅因为位表示是相同的,并且这允许一些方便的交叉情况,它们实际上并不是一回事。

引用

有关更多信息,请参见 comp.lang.c FAQ 的问题 5.3。 有关 C 标准,请参阅此 pdf。请查看第 6.3.2.3 节“指针”第 3 段。

评论

3赞 Sinan Ünür 8/19/2009
感谢您指向常见问题解答列表。但是,另请参阅 c-faq.com/null/nullor0.html
4赞 Johannes Schaub - litb 8/19/2009
不,你不会与全位零进行比较。这不是 ,但这是使用内置运算符的比较。一端是空指针常量,另一端是指针。以及带有 和 的其他两个版本。这三个人做同样的事情。ptrmemcmp'\0'NULL0
7赞 Johannes Schaub - litb 8/19/2009
您将内置比较运算符视为比较位字符串的东西。但事实并非如此。它比较两个值,这两个值是抽象概念。因此,无论其位字符串是什么样子,内部表示为 的 null 指针仍然是 null 指针,并且它仍然会与 、 和所有其他 null 指针常量形式进行比较。0xDEADBEEFNULL0\0
2赞 Andrew Keeton 8/19/2009
你对比较运算符提出了一个很好的观点。我复习了 C99。它说“值为 0 的整数常量表达式,或转换为类型 void * 的表达式,称为空指针常量。它还说字符文字是一个整数常量表达式。因此,通过传递属性,你是对的.ptr == '\0'
2赞 oggiemc 4/2/2014
"....也许可以 #undef NULL 并将其重新定义为古怪的东西。任何这样做的人都应该被枪毙。 我的好先生让我笑出声来......
1赞 John Millikin 8/19/2009 #2

NULL不保证为 0 -- 其确切值取决于体系结构。大多数主要体系结构将其定义为 。(void*)0

'\0'将始终等于 0,因为这是字节 0 在字符文字中的编码方式。

我不记得 C 编译器是否需要使用 ASCII——如果没有,可能并不总是等于 48。无论如何,除非您正在处理非常晦涩难懂的系统,否则您不太可能遇到使用替代字符集(如 EBCDIC)的系统。'0'

在 64 位系统上,各种类型的大小会有所不同,但整数值会相同。


一些评论者对 NULL 等于 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

评论

2赞 Chris Lutz 8/19/2009
OP 询问的是“\0”(NUL 字符),而不是“0”(零字符)
2赞 John Millikin 8/19/2009
@Chris:“\0”不是 NULL,它是字节 0,以字符文字中的八进制编码。
2赞 David Rodríguez - dribeas 8/19/2009
在 C++ 中,标准保证从整数值 0 到指针的转换将始终产生空指针。在 C++ 中,0 保证为空指针,而另一方面,NULL 是宏,恶意编码人员可以将其重新定义为不同的东西。
6赞 jalf 8/19/2009
NULL 保证为 0。NULL 指针的位模式不保证全部为零,但 NULL 常量始终为 0。
2赞 8/19/2009
你的第一句话是错误的 - NULL 在 C++ 中不能定义为 (void*)0,因为没有从 void * 到另一个指针的隐式转换(与 C 不同)。
3赞 peterb 8/19/2009 #3

“NUL”不是 0,而是指 ASCII NUL 字符。至少,这就是我看到它的使用方式。空指针通常定义为 0,但这取决于您运行的环境,以及您使用的任何操作系统或语言的规范。

在 ANSI C 中,空指针被指定为整数值 0。因此,任何不符合 ANSI C 的世界都不符合 ANSI C 标准。

3赞 richardtallent 8/19/2009 #4

值为 的字节是 ASCII 表上称为 或 的特殊字符。在 C 中,由于不应在源代码中嵌入控制字符,因此在带有转义 0 的 C 字符串中表示,即 .0x00NULNULL\0

但真正的 NULL 不是一个值。它是没有价值的。对于指针,这意味着指针没有可指向的内容。在数据库中,这意味着字段中没有值(这与说字段为空、0 或填充空格不同)。

给定系统或数据库文件格式用于表示 的实际值不一定是NULL0x00

18赞 Nasko 8/19/2009 #5

这三者都定义了零在不同上下文中的含义。

  • 指针上下文 - 使用 NULL,表示指针的值为 0,与它是 32 位还是 64 位无关(一种情况为 4 个字节,其他 8 个字节为零)。
  • 字符串上下文 - 表示数字零的字符的十六进制值为 0x30,而 NUL 字符的十六进制值为 0x00(用于终止字符串)。

当你看记忆时,这三个总是不同的:

NULL - 0x00000000 or 0x00000000'00000000 (32 vs 64 bit)
NUL - 0x00 or 0x0000 (ascii vs 2byte unicode)
'0' - 0x20

我希望这能澄清它。

评论

9赞 caf 8/19/2009
Nasko:评估并感到惊讶。sizeof('\0')
3赞 David Rodríguez - dribeas 8/19/2009
@Nasko:我真的很惊讶:使用 gcc,在 C 中:sizeof('\0') == sizeof('a') == 4,而使用 g++,在 C++中:sizeof('\0') == sizeof('a') == 1
1赞 David Rodríguez - dribeas 8/19/2009
@Nasko:来自 C 标准 (draft,n1124):“整数字符常量的类型为 int”,因此“\0”实际上是 C 中的 int 类型,因此在我的架构(linux,32 位)中 sizeof('\0') 为 4
0赞 Nasko 8/19/2009
@dribeas - 我不是把它描述为一个常量,而是你看到的字符串的一部分。我绝对可以明确地说出来。谢谢
0赞 chux - Reinstate Monica 9/23/2017
@DavidRodríguez-dribeas Undid edit “将'0' ASCII 值更正为 0x20 (dec 32)”
13赞 Sinan Ünür 8/19/2009 #6

如果 NULL 和 0 等效于 null 指针常量,我应该使用哪个?在 C FAQ 列表中也解决了这个问题:

C 程序员必须理解这一点,并且可以互换 指针上下文,并且取消强制转换是完全可以接受的。任何用法 NULL(与 相反)应为 认为这是一个温柔的提醒 指针被涉及;程序员 不应依赖它(对于 他们自己的理解或 compiler's) 用于区分指针和整数。NULL00000

只有在指针上下文中,和是等价的。 应该 当另一种是 必需的,即使它可能有效, 因为这样做会发送错误 文体信息。(此外,ANSI 允许定义 to be ,这在 所有这些都在非指针上下文中。在 特别,不要在 需要 ASCII 空字符 ()。 提供您自己的定义NULL0NULL0NULL((void *)0)NULLNUL

#define NUL '\0'

如果必须的话。

43赞 amaterasu 8/19/2009 #7

似乎很多人误解了 NULL、'\0' 和 0 之间的区别。所以,为了解释,并试图避免重复前面说过的话:

转换为 type 的值为 0 的 type 常量表达式或此类型的表达式转换为 type 是 null 指针常量,如果转换为指针,则该常量将成为 null 指针标准保证将不等于任何指向任何对象或函数的指针进行比较。intvoid *

NULL是一个宏,定义为 null 指针常量

\0是用于表示 null 字符的构造,用于终止字符串。

null 字符是所有位都设置为 0 的字节。

评论

2赞 Pacerier 7/19/2021
你错过了.0
7赞 Eugene Yokota 8/19/2009 #8

NULL、'\0' 和 0 有什么区别

“null 字符 (NUL)”是最容易排除的。 是字符文字。 在 C 中,它被实现为 ,因此,它与 0 相同,0 是 。在 C++ 中,字符文字实现为 ,即 1 个字节。这通常不同于 或 。'\0'intINT_TYPE_SIZEcharNULL0

Next, 是一个指针值,该值指定变量不指向任何地址空间。撇开它通常以零形式实现的事实不谈,它必须能够表达架构的完整地址空间。因此,在 32 位体系结构上,NULL (可能) 是 4 字节,而在 64 位体系结构上是 8 字节。这取决于 C 的实现。NULL

最后,文字的类型为 ,其大小为 。默认值可能因体系结构而异。0intINT_TYPE_SIZEINT_TYPE_SIZE

苹果写道:

Mac OS X 使用的 64 位数据模型称为“LP64”。这是 Sun 和 SGI 的其他 64 位 UNIX 系统以及 64 位 Linux 使用的通用数据模型。LP64 数据模型定义基元类型如下:

  • int 是 32 位
  • long 是 64 位
  • long-long 也是 64 位
  • 指针是 64 位

维基百科 64 位

Microsoft 的 VC++ 编译器使用 LLP64 模型。

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;
}

上面的代码在 gcc 上返回 4,在 g++ 上返回 1。

评论

2赞 caf 8/19/2009
否,不是 1 字节值。它是一个字符文字,它是一个整数常量表达式 - 所以如果可以说它有一个大小,那么它就是 的大小(必须至少是 2 个字节)。如果你不相信我,请自己评估并看看。,并且都是完全等价的。'\0'intsizeof('\0')'\0'00x0
0赞 Eugene Yokota 8/19/2009
@caf这取决于语言。如果你不相信我,请尝试使用 C++ 编译器。sizeof('\0')
2赞 Unused 2/26/2015
打印 sizeof(something) 时应使用“%zu”
0赞 12/25/2021
在 C 语言中,您的计算机上它是 4,只是因为默认为 int 的自动投射。在不重铸的情况下将该值分配给 char、int 或 long long int,其大小将相应更改。此外,“a”的大小是可变的 4 分之一。
4赞 EvilTeach 8/19/2009 #9

一个 L NUL,它结束一个字符串。

两个 L 的 NULL 表示什么都没有。

我敢打赌一头金牛

没有三升的 NULLL。

你如何处理NUL?

5赞 dlmeetei 11/4/2013 #10

在开始使用 C 语言时,它对我有帮助的一篇很好的文章(摘自 Linden 的 Expert C Programming)

一个 'l' nul 和两个 'l' null

记住这个小韵律,以回忆指针和 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. 
  • 位模式为零的 ASCII 字符称为“NUL”。
  • 表示指针不指向任何地方的特殊指针值为“NULL”。
  • 这两个术语在含义上不可互换。

评论

0赞 glglgl 11/13/2014
简单得多:是一个控制代码,如、、等,因此最多有 3 个字符。NULBELVTHTSOT
-2赞 shinxg 9/20/2017 #11

(void*) 0 为 NULL,“\0”表示字符串的末尾。