在C中,各种零值之间似乎存在差异 - NULL
,NUL
和0
。
我知道ASCII字符'0'
评估为48
或0x30
。
NULL
指针通常定义为:
#define NULL 0
或者
#define NULL (void *)0
此外,NUL
字符'\0'
似乎也会评估为0
。
是否有时候这三个值不相等?
在64位系统上也是如此吗?
答案 0 :(得分:322)
注意:此答案适用于C语言,而不适用于C ++。
整数常量文字0
具有不同的含义,具体取决于使用它的上下文。在所有情况下,它仍然是一个整数常量,其值为0
,它只是以不同的方式描述。
如果将指针与常量文字0
进行比较,则检查指针是否为空指针。然后将此0
称为空指针常量。 C标准定义强制转换为类型0
的{{1}}是空指针和空指针常量。
此外,为了帮助提高可读性,请在头文件void *
中提供宏NULL
。根据您的编译器,可能stddef.h
并将其重新定义为古怪的东西。
因此,这里有一些检查空指针的有效方法:
#undef NULL
if (pointer == NULL)
被定义为比较等于空指针。实现定义NULL
的实际定义是什么,只要它是一个有效的空指针常量。
NULL
if (pointer == 0)
是空指针常量的另一种表示。
0
此if (!pointer)
语句隐式检查“不为0”,因此我们将其反转为“is 0”。
以下是检查空指针的INVALID方法:
if
对于编译器,这不是检查空指针,而是检查两个变量。如果mynull从未在代码中发生变化,并且编译器优化常量将0折叠到if语句中,则此可能有效,但这不能保证,并且编译器必须至少生成一条诊断消息(警告或错误) )根据C标准。
请注意,C语言中的空指针是什么。它与底层架构无关。如果底层架构的空指针值定义为地址0xDEADBEEF,那么由编译器来解决这个问题。
因此,即使在这个有趣的架构上,以下方法仍然是检查空指针的有效方法:
int mynull = 0;
<some code>
if (pointer == mynull)
以下是检查空指针的INVALID方法:
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'
整数常量 - 唯一的区别在于它传达给人类读者的 intent (“我用它作为一个空字符。“)。
有关详情,请参阅Question 5.3 of the comp.lang.c FAQ。 有关C标准,请参阅this pdf。请查看6.3.2.3指针,第3节。
答案 1 :(得分:32)
似乎很多人误解了NULL,'\ 0'和0之间的区别。所以,要解释,并试图避免重复前面说过的事情:
int类型的常量表达式,其值为0,或者此类型的表达式,强制转换为类型void *是空指针常量,如果转换为指针,则变为空指针。标准保证将不等于任何指向任何对象或函数的指针。
NULL 是一个宏,以空指针常量定义。
'\ 0'是一种用于表示空字符的构造,用于终止字符串。
空字符是一个字节,其所有位都设置为0。
答案 2 :(得分:14)
所有三个都在不同的语境中定义零的含义。
当你查看记忆时,这三个总是不同的:
NULL - 0x00000000 or 0x00000000'00000000 (32 vs 64 bit)
NUL - 0x00 or 0x0000 (ascii vs 2byte unicode)
'0' - 0x20
我希望这能澄清它。
答案 3 :(得分:6)
If NULL and 0 are equivalent as null pointer constants, which should I use?也解决了这个问题:
C程序员必须明白这一点
NULL
和0
可以互换 指针上下文,以及uncast0
完全可以接受。任何用法 应该是NULL(而不是0
) 被认为是一个温和的提醒 涉及指针;程序员 不应该依赖它(无论是为了 他们自己的理解还是 编译器用于区分指针0
来自整数0
。仅在指针上下文中
NULL
和0
是等效的。NULL
应该 当另一种0
时,不要使用它 要求,即使它可能有效, 因为这样做会发错 风格的信息。 (此外,ANSI 允许NULL
的定义((void *)0)
,无法使用 所有在非指针上下文中。)在 特别是,当使用时不要使用NULL
需要ASCII空字符(NUL
)。 提供您自己的定义
#define NUL '\0'
如果必须的话。
答案 4 :(得分:5)
NULL,'\ 0'和0
之间有什么区别
“null character(NUL)”最容易排除。 '\0'
是一个字符文字。
在C中,它实现为int
,因此,它与0相同,即INT_TYPE_SIZE
。在C ++中,字符文字实现为char
,即1个字节。这通常与NULL
或0
不同。
接下来,NULL
是一个指针值,指定变量不指向任何地址空间。抛开它通常被实现为零的事实,它必须能够表达体系结构的完整地址空间。因此,在32位架构上,NULL(可能)是4字节,64位架构是8字节。这取决于C的实现。
最后,文字0
的类型为int
,其大小为INT_TYPE_SIZE
。 INT_TYPE_SIZE
的默认值可能因架构而异。
Mac OS X使用的64位数据模型称为“LP64”。这是Sun和SGI以及64位Linux的其他64位UNIX系统使用的通用数据模型。 LP64数据模型定义了基本类型,如下所示:
- 整数是32位
- longs是64位
- long-longs也是64位
- 指针是64位
维基百科64-bit:
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。
答案 5 :(得分:4)
答案 6 :(得分:3)
从C开始帮助我的一件好事(取自林登的专家C编程)
One'l'nul和Two'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”。这两个术语不可互换 含义。
答案 7 :(得分:2)
“NUL”不为0,但是指的是ASCII NUL字符。至少,这就是我看过它的用法。空指针通常定义为0,但这取决于您运行的环境,以及您正在使用的操作系统或语言的规范。
在ANSI C中,空指针被指定为整数值0.因此,任何不符合ANSI C的世界都不符合ANSI C。
答案 8 :(得分:0)
值为0x00的字节在ASCII表上是名为“NUL”或“NULL”的特殊字符。在C中,由于您不应在源代码中嵌入控制字符,因此在带有转义为0的C字符串中表示,即“\ 0”。
但是真正的NULL 不是一个值。这是缺乏价值。对于指针,这意味着指针没有任何指向。在数据库中,这意味着字段中没有值(这与字段为空,0或填充空格不同)。
给定系统或数据库文件格式用于表示NULL的实际值不一定是0x00。
答案 9 :(得分:-1)
NULL
不保证为0 - 其确切值取决于架构。大多数主要架构将其定义为(void*)0
。
'\0'
将始终等于0,因为这就是字符0在字符文字中的编码方式。
我不记得C编译器是否需要使用ASCII - 如果不是,'0'
可能并不总是等于48.无论如何,你不可能遇到一个使用替代字符集的系统EBCDIC,除非您正在使用非常模糊的系统。
各种类型的大小在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
答案 10 :(得分:-2)
(void *)0为NULL,&#39; \ 0&#39;表示字符串的结尾。