提问人:gnavi 提问时间:8/19/2009 最后编辑:John Kugelmangnavi 更新时间:2/23/2021 访问量:404815
NULL、'\0' 和 0 有什么区别?
What is the difference between NULL, '\0' and 0?
问:
在 C 中,零 -- , 和 的各种值之间似乎存在差异。NULL
NUL
0
我知道 ASCII 字符的计算结果为 或 。'0'
48
0x30
指针通常定义为:NULL
#define NULL 0
或
#define NULL (void *)0
另外,似乎也有评价的性格。NUL
'\0'
0
有没有这三个值不能相等的时候?
在 64 位系统上也是如此吗?
答:
注意:这个答案适用于 C 语言,而不是 C++。
Null 指针
整数常量文本具有不同的含义,具体取决于使用它的上下文。在所有情况下,它仍然是一个具有值的整数常数,只是以不同的方式描述。0
0
如果将指针与常量文本进行比较,则这是检查指针是否为空指针的检查。然后,这称为 null 指针常量。C 标准定义强制转换为类型既是空指针又是空指针常量。0
0
0
void *
此外,为了提高可读性,头文件中提供了宏。根据您的编译器,可能会将其重新定义为古怪的东西。NULL
stddef.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 段。
评论
ptr
memcmp
'\0'
NULL
0
0xDEADBEEF
NULL
0
\0
ptr == '\0'
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
评论
“NUL”不是 0,而是指 ASCII NUL 字符。至少,这就是我看到它的使用方式。空指针通常定义为 0,但这取决于您运行的环境,以及您使用的任何操作系统或语言的规范。
在 ANSI C 中,空指针被指定为整数值 0。因此,任何不符合 ANSI C 的世界都不符合 ANSI C 标准。
值为 的字节是 ASCII 表上称为 或 的特殊字符。在 C 中,由于不应在源代码中嵌入控制字符,因此在带有转义 0 的 C 字符串中表示,即 .0x00
NUL
NULL
\0
但真正的 NULL 不是一个值。它是没有价值的。对于指针,这意味着指针没有可指向的内容。在数据库中,这意味着字段中没有值(这与说字段为空、0 或填充空格不同)。
给定系统或数据库文件格式用于表示 的实际值不一定是 。NULL
0x00
这三者都定义了零在不同上下文中的含义。
- 指针上下文 - 使用 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
我希望这能澄清它。
评论
sizeof('\0')
如果 NULL 和 0 等效于 null 指针常量,我应该使用哪个?在 C FAQ 列表中也解决了这个问题:
C 程序员必须理解这一点,并且可以互换 指针上下文,并且取消强制转换是完全可以接受的。任何用法 NULL(与 相反)应为 认为这是一个温柔的提醒 指针被涉及;程序员 不应依赖它(对于 他们自己的理解或 compiler's) 用于区分指针和整数。
NULL
0
0
0
0
0
只有在指针上下文中,和是等价的。 应该 当另一种是 必需的,即使它可能有效, 因为这样做会发送错误 文体信息。(此外,ANSI 允许定义 to be ,这在 所有这些都在非指针上下文中。在 特别,不要在 需要 ASCII 空字符 ()。 提供您自己的定义
NULL
0
NULL
0
NULL
((void *)0)
NULL
NUL
#define NUL '\0'
如果必须的话。
似乎很多人误解了 NULL、'\0' 和 0 之间的区别。所以,为了解释,并试图避免重复前面说过的话:
转换为 type 的值为 0 的 type 常量表达式或此类型的表达式转换为 type 是 null 指针常量,如果转换为指针,则该常量将成为 null 指针。标准保证将不等于任何指向任何对象或函数的指针进行比较。int
void *
NULL
是一个宏,定义为 null 指针常量。
\0
是用于表示 null 字符的构造,用于终止字符串。
null 字符是所有位都设置为 0 的字节。
评论
0
NULL、'\0' 和 0 有什么区别
“null 字符 (NUL)”是最容易排除的。 是字符文字。
在 C 中,它被实现为 ,因此,它与 0 相同,0 是 。在 C++ 中,字符文字实现为 ,即 1 个字节。这通常不同于 或 。'\0'
int
INT_TYPE_SIZE
char
NULL
0
Next, 是一个指针值,该值指定变量不指向任何地址空间。撇开它通常以零形式实现的事实不谈,它必须能够表达架构的完整地址空间。因此,在 32 位体系结构上,NULL (可能) 是 4 字节,而在 64 位体系结构上是 8 字节。这取决于 C 的实现。NULL
最后,文字的类型为 ,其大小为 。默认值可能因体系结构而异。0
int
INT_TYPE_SIZE
INT_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。
评论
'\0'
int
sizeof('\0')
'\0'
0
0x0
sizeof('\0')
一个 L NUL,它结束一个字符串。
两个 L 的 NULL 表示什么都没有。
我敢打赌一头金牛
没有三升的 NULLL。
在开始使用 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”。
- 这两个术语在含义上不可互换。
评论
NUL
BEL
VT
HT
SOT
(void*) 0 为 NULL,“\0”表示字符串的末尾。
评论
NUL
'\0'