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


309

在C中,似乎有零各个值之间的差- NULLNUL0

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

NULL指针通常定义为:

#define NULL 0

要么

#define NULL (void *)0

另外,似乎还有一个NUL性格'\0'值得评价的人物0

是否有时这三个值不能相等?

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



7
标识符NUL在C标准语言或库(或据我所知的C ++)中不存在。空字符有时称为NUL,但通常使用C或C ++来表示'\0'
Keith Thompson

Answers:


351

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


空指针

整数常量文字0根据其使用的上下文具有不同的含义。在所有情况下,它仍然是带有值的整数常量,0只是以不同的方式进行了描述。

如果将指针与常量文字进行比较0,则将检查该指针是否为空指针。这0随后被称为一个空指针常数。C标准定义0强制类型转换void *为空指针和空指针常量。

另外,为了提高可读性,宏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'被定义为空字符-所有位都设置为零的字符。这与指针无关。但是,您可能会看到类似于以下代码的内容:

if (!*string_pointer)

检查字符串指针是否指向空字符

if (*string_pointer)

检查字符串指针是否指向非空字符

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

此外,'\0'(与所有字符文字一样)是一个整数常量,在这种情况下,其值为零。因此,'\0'它完全等同于一个未经修饰的0整数常量-唯一的区别在于它传达给人类读者的意图(“我将其用作空字符”。)。

参考文献

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


3
感谢您指向FAQ列表。然而,也看到c-faq.com/null/nullor0.html
思南Ünür

4
不,您不会将其ptrall-bits-zero进行比较。这不是memcmp,而是使用内置运算符的比较。一侧是空指针常量'\0',另一侧是指针。藏汉与其它两个版本NULL0。这三个人做同样的事情。
Johannes Schaub-litb

6
您将内置的比较运算符当作可以比较位字符串的东西。但这不是事实。它比较了两个值,它们是抽象概念。因此,一个空指针在内部表示为0xDEADBEEF仍然是一个空指针,无论其位串看起来像什么,它仍然会比较等于NULL0\0和所有其他空指针常量形式。
Johannes Schaub-litb

2
您对比较运算符很清楚。我复习了C99。它说:“一个值为0的整数常量表达式,或将这种类型强制转换为void *的表达式,称为空指针常量。” 它还说字符文字是整数常量表达式。因此,通过传递属性,您是对的ptr == '\0'
安德鲁·基顿

2
“...。可能可以#undef NULL并将其重新定义为古怪的东西。任何这样做的人都应该被枪杀。” 这是我的好先生,让我大声笑出来
oggiemc 2014年

34

似乎许多人误解了NULL,'\ 0'和0之间的区别。因此,为了解释,并试图避免重复前面所说的事情:

类型的常量表达式int与值0,或这种类型的表达,浇铸到类型void *是一个空指针常数,其中,如果转换为指针变成空指针。该标准保证比较不等于指向任何对象或函数的任何指针

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

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

一个空字符是有它的所有位设置为0字节。


14

这三个在不同上下文中定义零的含义。

  • 指针上下文-使用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

我希望这可以澄清它。


8
Nasko:评估sizeof('\0')并感到惊讶。
caf

3
@Nasko:我真的很惊讶:使用gcc,在C中:sizeof('\ 0')== sizeof('a')== 4,而使用g ++,在C ++中:sizeof('\ 0')== sizeof ('a')== 1
大卫·罗德里格斯(DavidRodríguez)-dribeas,2009年

1
@Nasko:从C标准开始(草稿,n1124):'一个整数字符常量的类型为int',因此'\ 0'在C中实际上为int类型,因此在我的体系结构中sizeof('\ 0')为4 (linux,32bit)
DavidRodríguez-dribeas

@dribeas-我不是将其描述为常量,而是将其描述为字符串的一部分。我绝对可以明确地说出来。谢谢
纳斯科(Nasko)2009年

@DavidRodríguez-dribeas无需编辑“将'0'ASCII值更正为0x20(12月32日)”
chux-恢复莫妮卡

6

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

C程序员必须了解这一点 NULL0并且可以在指针上下文中互换,并且0 完全可以接受未强制转换。NULL的任何用法(相对于0)都应被视为一种温和的提示,即涉及到一个指针。程序员不应该依靠它(无论是出于自己的理解还是编译器的观点)来区分指针 0和整数0

仅在指针上下文中 NULL0是等效的。即使可能需要NULL使用另一种方法也不应该使用0它,因为这样做会发送错误的样式信息。(此外,ANSI允许NULL对be进行 定义((void *)0),这在非指针上下文中根本不起作用。)尤其是NULL当需要ASCII空字符(NUL)时,请勿使用。提供您自己的定义

#define NUL '\0'

如果你必须。


5

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

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

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

最后,文字0是type int,它是size INT_TYPE_SIZE。的默认值INT_TYPE_SIZE可能会根据体系结构而有所不同。

苹果写道:

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

  • 整数是32位
  • long是64位
  • 长整型也是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
不,'\0'不是 1个字节的值。这是一个字符文字,它是一个整数常量表达式-因此,如果可以说它具有大小,那么它就是的大小int(必须至少2个字节)。如果您不相信我,sizeof('\0')请自己评估一下。 '\0'0并且0x0完全等效。
caf

@caf取决于语言。如果您不相信我,请尝试sizeof('\0')使用C ++编译器。
尤金·横田

2
您在打印sizeof(something)时应使用“%zu”
2015年


4

一篇很好的文章,对我使用C很有帮助(摘自Linden的Expert C编程)

一个'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是控制码,例如BELVTHTSOT等等,因而具有最高 3个字符。
glglgl 2014年

2

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

在ANSI C中,将空指针指定为整数值0。因此,任何不正确的世界都不符合ANSIC。


1

0x00在ASCII表上,值为的字节是称为NUL或的特殊字符NULL。在C语言中,由于您不应该在源代码中嵌入控制字符,因此它在C字符串中以转义的0表示,即\0

但是,真正的NULL 不是值。这是缺乏价值。对于指针,这意味着该指针没有指向任何对象。在数据库中,这意味着字段中没有值(这与说字段为空白,0或由空格填充不同)。

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


0

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

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

我不记得是否要求C编译器使用ASCII -如果不是,则'0'可能不总是等于48。无论如何,除非您正在从事非常复杂的工作,否则不太可能会遇到使用EBCDIC之类的替代字符集的系统。晦涩的系统。

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


一些评论者表示怀疑,空等于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
OP询问的是“ \ 0”(NUL字符),而不是“ 0”(零字符)
Chris Lutz

2
@Chris:“ \ 0”不为NULL,它是字符文字中以八进制编码的字节0。
约翰·米利金

2
在C ++中,该标准保证从整数值0到指针的转换将始终产生空指针。在C ++中,保证0为空指针,而另一方面,NULL是一个宏,恶意编码器可能会将其重新定义为不同的东西。
大卫·罗德里格斯(DavidRodríguez)-dribeas,2009年

6
并且NULL保证为0。不能保证NULL指针的位模式全为零,但是NULL常数始终是
0。– jalf

2
您的第一句话是错误的-NULL不能在C ++中定义为(void *)0,因为没有从void *到另一个指针的隐式转换(与C中不同)。

-2

(void *)0为NULL,并且'\ 0'表示字符串的结尾。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.