76

假设NULL在 C 中总是转换为 false 是否安全?

void *somePtr = NULL;

if (!somePtr) {
  /* This will always be executed? */
}

还是应该对 的值进行明确的检查NULL

4

13 回答 13

79

是的。NULL 的计算结果为假,因为 C 认为任何非零值为真,任何零值为假。NULL 本质上是zero地址,并且在比较中被视为这样,我相信会被提升为 int 以进行布尔检查。我希望任何熟悉 C 的人都可以阅读您的代码,尽管我可能会明确地进行检查。

在 C 和 C++ 编程中,保证两个空指针比较相等;ANSI C 保证任何空指针在与整数类型比较时都等于 0;此外,宏 NULL 被定义为空指针常量,即值为 0(作为整数类型或转换为指向 void 的指针),因此空指针将与 NULL 比较。

参考:http ://en.wikipedia.org/wiki/Null_pointer#Null_pointer

于 2009-01-20T00:38:18.120 回答
21

'C' 语言可以追溯到 (void*)0 实际上可以是有效指针的时代。不久前,8080 和 Z80 微处理器在地址 0 处有一个中断向量。面对这样的架构选择,它只能让头文件声明 NULL 的值。那里有一些编译器,现在早已被遗忘,其中 NULL 不等于 (void*)0 (0xffff 是下一个替代方案),从而使您的 if() 语句具有未定义的行为。

C++ 仁慈地结束了这一点,空指针可以从 0 分配和测试。

于 2009-01-20T00:56:59.597 回答
19

假设任何事情都不安全。

显式检查也更清楚您正在测试什么。

于 2009-01-20T00:34:24.777 回答
15

是(至少对于任何符合标准的 C 编译器!)

comp.lang.c 常见问题解答

问:用于测试非空指针的缩写指针比较“if(p)”是否有效?如果空指针的内部表示不为零怎么办?

答:总是有效的。

于 2009-01-20T01:24:33.520 回答
10

我的 ISO/IEC 9899:TC3(委员会草案 — 2007 年 9 月 7 日)副本说:

6.3 转换

1 几个运算符自动将操作数值从一种类型转换为另一种类型。

6.3.2.3 指针

3 值为 0 [...] 的整数常量表达式称为空指针常量。如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证与指向任何对象或函数的指针不相等。

到目前为止,ptr!=0对于每个 non-null 都是 true (1) ptr,但它仍然是开放的,两个空指针如何比较。

6.5.9 等式运算符

5 [...] 如果一个操作数是指针而另一个是空指针常量,则空指针常量将转换为指针的类型。

6 两个指针比较相等当且仅当两者都是空指针时,两者都是 [...]

因此,ptr==0是 1(并且ptr!=0是 0),当且仅当ptr是一个空指针。

6.5.3.3 一元算术运算符

5 逻辑否定运算符的结果!如果其操作数的值比较不等于 0,则为 0,如果其操作数的值比较等于 0,则为 1。结果的类型为 int。表达式 !E 等价于 (0==E)。

所以同样适用于!ptr

6.8.4.1 if 语句

1 if 语句的控制表达式应具有标量类型。

2 在这两种形式中,如果表达式比较不等于 0,则执行第一个子语句。

注意,标量类型算术类型指针类型(参见“6.2.5 类型”,第 21 节)。放在一起,我们有:

  • if (ptr)成功 ⇔ptr!=0是 1 ⇔ptr不是空指针。
  • if (!ptr)成功 ⇔ptr==0是 1 ⇔ptr是空指针。
于 2019-11-25T14:49:24.907 回答
5

是的,if(!p)有效并保证有效。

值为 0 的整型常量表达式或转换为 void * 类型的表达式称为空指针常量。如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证与指向任何对象或函数的指针不相等。

https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p3

这意味着这(void*)0是一个空指针。这也意味着 ifp是一个指针,thenp==0等价于p==(void*)0.

这也意味着如果p不是一个空指针,那么p==(void*)0将评估为0

到现在为止还挺好。

将空指针转换为另一种指针类型会产生该类型的空指针。任何两个空指针应该比较相等。

http://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p4

请注意,“任何两个空指针都应比较相等。” 这意味着如果p是一个空指针,那么p==0将评估为真,因为0将提升到(void*)0哪个是空指针。这也意味着没有非空指针可以等于空指针。

让我们看一下否定运算符。

逻辑否定运算符的结果!如果其操作数的值比较不等于 0,则为 0,如果其操作数的值比较等于 0,则为 1。结果的类型为 int。表达式 !E 等价于 (0==E)。

http://port70.net/~nsz/c/c11/n1570.html#6.5.3.3p5

这告诉我们,!pp==0定义相同,p==(void*)0与上面提到的相同。

考虑到所有空指针都相等这一事实,这意味着如果是空​​指针,p==(void*)0则只能评估为真,如果p不是空指针,则只能评估为假p

所以是的,这是检查是否为空指针if(!p)的一种非常安全的方法。p

于 2019-11-22T15:21:16.417 回答
4

NULL 只是一个预处理器定义。它在 stdio.h 中。通常,只有疯子才会重新定义它,但这是可能的。一个例子:

#include <stdio.h>
#ifdef NULL
#undef NULL
#endif
#define NULL 1

void main()
{

        if (NULL)
                printf("NULL is true\n");
        else
                printf("NULL is false\n");
}

此代码将打印“NULL 为真”。如果您不相信我,请尝试一下。您的编译器甚至可能不会警告您您正在做一些奇怪的事情。

于 2009-01-20T03:56:29.407 回答
2


什么是空值?

宏 NULL 在 <stddef.h> (和其他头文件)中定义为空指针常量


空指针常量的值是多少?

值为0的整数常量表达式,或转换为 void * 类型的此类表达式称为空指针常量。

示例定义:

#define NULL ((void*)0)


评估 if(NULL)

if ( 表达式 ) 语句

if ( 表达式 ) 语句 else 语句

在这两种形式中,如果表达式比较不等于 0,则执行第一个子语句。在 else 形式中,如果表达式比较相等,则执行第二个子语句 §6.8.4.1 语言 133 ISO/IEC 9899:TC3 委员会草案 — 9 月 7 日, 2007 WG14/N1256 为 0。如果通过标签到达第一个子语句,则不执行第二个子语句。


所以是的,如果编译器符合 ISO C99,您可以假设下面的语句将始终执行。

if (!NULL) { statement; } 


以上引用来自 ISO/IEC 9899:1999 (C99)。你可以在这里阅读。

于 2019-11-29T18:44:44.837 回答
2

是的,它:

C 标准 6.3.2.3

值为 0 的整型常量表达式或转换为 void * 类型的表达式称为空指针常量。如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证比较不等于指向任何对象或函数的指针。

和 6.3.2.6

任何指针类型都可以转换为整数类型。除非前面指定,结果是实现定义的。如果结果不能以整数类型表示,则行为未定义。结果不必在任何整数类型的值范围内。

-

当任何标量值转换为 _Bool 时,如果该值比较等于 0,则结​​果为 0;否则,结果为 1

于 2019-11-29T19:30:45.610 回答
0

NULL被定义为一个常量指针,它保证指向内存中一个无用/不存在的地方。的大多数实现NULL是,((void *)0)但这不是强制性的。

于 2009-01-20T00:35:18.643 回答
0

在我看来,假设这一点并不总是安全的。因为,根据程序中包含的头文件,它可以被重新定义。但是按照标准,空指针常量保证不指向任何真实对象,并且有一个类型void *

在我们的例子中,声明void *somePtr = NULL也可以void *somePtr = 00空指针。

“值为 0 的整型常量表达式,或这种类型转换为 void * 的表达式,称为空指针常量。如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证与指向任何对象或函数的指针不相等。” https://www.geeksforgeeks.org/few-bytes-on-null-pointer-in-c/

这只是意味着,*somePtr在该特定点进行评估可能会导致错误。

另一个参考可以是https://www.gnu.org/software/libc/manual/pdf/libc.pdf在第 944 A.3 页关于 NULL 指针常量

于 2019-11-30T06:52:12.103 回答
-2

是的,主要是。

首先,NULL 是一个 typedef。我可以通过在以前包含的标题中说出来来把你搞砸

#define NULL 1

这可能没有多大意义,但是从什么时候开始,其他人的代码才有意义呢?:)

此外,虽然它在语法上可能是安全的,但在语义上并不正确。NULL 表示“无”,既不是真或假,也不是布尔值、int 或字符串。它的意思是“一无所有的象征”。所以测试 NULL 更像是一个哲学问题:如果一棵树倒在森林里,并且if(listener),它会发出声音吗?

帮大家一个忙,并明确针对 NULL 进行测试。

于 2009-01-20T00:58:06.037 回答
-6

*NULL 始终以 0x00L 为目标。您可以认为这是错误的,但要确保始终进行明确的检查。

于 2009-01-20T00:35:49.030 回答