在C中,零值的不同值--NULLNUL0之间似乎存在差异.

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

NULL指针通常定义为:

#define NULL 0

#define NULL (void *)0

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

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

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

推荐答案

Note:这个答案适用于C语言,而不是C++.


空指针

整数常量文字0根据其使用的上下文具有不同的含义.在所有情况下,它仍然是值为0的整数常量,只是用不同的方式描述而已.

如果要将指针与常量文本0进行比较,那么这是一个判断,以查看指针是否为空指针.这0随后被称为空指针常量.C标准定义了类型void *0转换既是空指针又是空指针常量.

此外,为了帮助可读性,在头文件stddef.h中提供宏NULL.根据你的编译器,你可能会把它重新定义为一些古怪的东西.

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

if (pointer == NULL)

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

if (pointer == 0)

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

if (!pointer)

if条语句隐式地判断"不是0",所以我们将其反转为"是0".

以下是判断空指针的无效方法:

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

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

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

因此,即使在这种有趣的体系 struct 上,以下方法仍然是判断空指针的有效方法:

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

以下是判断空指针的无效方法:

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

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

空字符

'\0'被定义为空字符,即所有位都设置为零的字符.'\0'(和所有字符文字一样)是一个整数常量,在本例中为零.所以'\0'完全等同于一个未经修饰的0整型常量——唯一的区别在于它传递给人类读者的intent("我把它用作空字符").

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

if (!*char_pointer)

判断字符指针是否指向空字符.

if (*char_pointer)

判断字符指针是否指向非空字符.

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

参考文献

更多信息请参见Question 5.3 of the comp.lang.c FAQ.

C++相关问答推荐

函数指针始终为零,但在解除引用和调用时有效

为什么即使在强制转换时,此代码也会溢出?

_泛型控制表达式涉及数组碰撞警告的L值转换错误?

轮询libusb_pollfd struct 列表的正确方式是什么?

错误Cygwin_Except::Open_stackdupfile:正在转储堆栈跟踪是什么?

如何计算打印二叉搜索树时每行所需的空间?

I2C外设在单次交易后出现故障

关于";*(++p)->;t";、&++p->;t";和&q;++*p->;t";的问题

我的C函数起作用了,但我不确定为什么

编译器如何处理具有更复杂值的枚举?

Wcstok导致分段故障

C程序向服务器发送TCPRST

为什么WcrTomb只支持ASCII?

Valgrind用net_pton()抱怨

如何在C中定义指向函数的指针并将该指针赋给函数?

即使我在C++中空闲,也肯定会丢失内存

为什么一个在线编译器拒绝这个VLA代码,而本地的Apple clang却不拒绝;t?

与指针的原始C数组或C++向量<;向量<;双>>;

为什么<到达*时不会转换为>?

如何用用户输入的多个字符串填充数组?