NULL, '\0'和0 ?

在C语言中,不同的0值之间似乎存在差异——NULLNUL0

我知道ASCII字符'0'计算为480x30

NULL指针通常定义为:

#define NULL 0

#define NULL (void *)0

此外,还有NUL字符'\0',它的计算结果似乎也是0

是否存在这三个值不能相等的情况?

在64位系统上也是这样吗?

378335 次浏览

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


空指针

整数常量字面值0根据所使用的上下文有不同的含义。在所有情况下,它仍然是一个值为0的整数常量,只是用不同的方式描述它。

如果将指针与常量常量0进行比较,则检查指针是否为空指针。这个0随后被称为空指针常量。C标准定义,转换为void *类型的0既是空指针,也是空指针常量。

此外,为了提高可读性,宏NULL在头文件stddef.h中提供。取决于你的编译器,可能会#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整数常量——唯一的区别是它传递给人类读者的意图(“我将此用作空字符。&;)”)。

'\0'与指针无关。然而,你可能会看到类似于下面代码的东西:

if (!*char_pointer)

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

if (*char_pointer)

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

不要把它们和空指针搞混了。只是因为位表示是相同的,这允许一些方便的交叉情况,它们实际上不是同一件事。

参考文献

参见comp.lang.c FAQ中的5.3问题获取更多信息。 C标准参见这个pdf。请看第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

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

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

在ASCII表中,值为0x00的字节是称为NULNULL的特殊字符。在C语言中,因为你不应该在源代码中嵌入控制字符,所以这是用C字符串表示的,带有转义0,即\0

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

给定的系统或数据库文件格式用来表示NULL实际值不一定是0x00

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

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

当你查看内存时,这三个总是不同的:

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

我希望这能解释清楚。

C常见问题列表中的如果NULL和0是等价的空指针常数,我应该使用哪个?也解决了这个问题:

C程序员必须理解这一点 NULL0是可互换的 指针上下文,那是一个未强制转换的0 完全可以接受。任何使用 NULL(相对于0)应该是 我认为这是一个温柔的提醒 指针涉及;程序员 不应该依赖它(either for 自己的理解也好 编译器)用于区分指针 0's from integer 0's.

只有在指针上下文中 NULL0是等价的。NULL应该 当另一种0被使用时,不能被使用 这是必需的,尽管可能有用, 因为这样做会产生错误的结果 风格信息。(此外,ANSI 允许NULL的定义为 ((void *)0),这将不会工作 所有这些都在非指针上下文中。)在 时,不要使用NULL 需要ASCII空字符(NUL)。 提供你自己的定义

#define NUL '\0'

如果你一定要的话。

似乎很多人误解了NULL、'\0'和0之间的区别。为了避免重复之前说过的话,我来解释一下:

类型为int的值为0的常量表达式,或此类型的表达式,转换为类型void *空指针常量,如果转换为指针则变成空指针。标准保证比较不等于指向任何对象或函数的任何指针

NULL是一个宏,在空指针常量中定义。

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

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

NULL, ' \0 '和0之间的区别是什么

"null character (NUL)"是最容易排除的。'\0'是一个字符字面值。 在C语言中,它被实现为int,因此,它与0相同,后者属于INT_TYPE_SIZE。在c++中,字符字面值被实现为char,它是1字节。这通常不同于NULL0

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

最后,字面量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位:

微软的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       ?
< p > 编辑:

#include <stdio.h>


int main(void) {
printf("%d", sizeof('\0'));
return 0;
}

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

一个1 - l的NUL,它结束一个字符串。

一个2l的NULL不指向任何东西。

我要赌一只金牛

没有3l null。

你如何处理NUL?< / >

一篇帮助我开始学习C语言的好文章(摘自Linden的Expert C Programming)

一个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.
  • 位模式为0的ASCII字符被称为“null”。
  • 表示指针不指向任何地方的特殊指针值是"NULL"。
  • 这两个词在意思上是不可互换的。

(void*) 0是NULL, '\0'表示字符串的结束。