是否可以安全地假设NULL
在C中始终转换为false?
void *somePtr = NULL;
if (!somePtr) {
/* This will always be executed? */
}
或者是否应该对NULL
的值进行明确检查?
答案 0 :(得分:49)
是。 NULL的计算结果为false,因为C认为任何非零值为true,任何零值为false。 NULL本质上是zero
地址,并且在比较中被视为这样,并且我相信将被提升为布尔检查的int。我希望你的代码对任何熟悉C的人都是可读的,尽管我可能会明确地进行检查。
在C和C ++编程中,两个为null 指针保证比较 等于; ANSI C保证任何null 指针在a中等于0 与整数类型比较; 此外,定义了宏NULL 作为空指针常量,即 值0(作为整数类型或 转换为指向void的指针,所以a 空指针将比较等于 NULL。
答案 1 :(得分:16)
假设任何事都是不安全的。
对您正在测试的内容进行明确检查也很清楚。
答案 2 :(得分:15)
'C'语言可以追溯到一个时代,其中(void *)0实际上可以是一个有效的指针。不久之前,8080和Z80微处理器在地址0处有一个中断向量。面对这样的架构选择,除了让头文件声明NULL值之外,它什么也做不了。那里有一些编译器,现在很久都被遗忘了,其中NULL不等于(void *)0(0xffff是下一个选择),因此给你的if()语句定义了未定义的行为。
C ++仁慈地结束了这一点,一个空指针可以从0分配和测试。
答案 3 :(得分:11)
答案 4 :(得分:7)
我的ISO / IEC 9899:TC3(委员会草案,2007年9月7日)副本:
6.3转换
1多个运算符会自动将操作数值从一种类型转换为另一种类型。
6.3.2.3指针
3值为0 [...]的整数常量表达式称为空指针常量。如果将空指针常量转换为指针类型,则可以保证生成的指针(称为空指针)与指向任何对象或函数的指针不相等。
到目前为止,ptr!=0
对每个非null ptr
都是true(1),但是它仍然是开放的,如何比较两个null指针。
6.5.9相等运算符
5 [...]如果一个操作数是一个指针,另一个是空指针常量,则该空指针常量将转换为指针的类型。
6当且仅当两个都是空指针,两个都是[...]
时,两个指针比较相等
因此,当且仅当ptr==0
为空指针时,ptr!=0
为1(而ptr
为0)。
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
为空指针。答案 5 :(得分:5)
NULL只是一个预处理器定义。它在stdio.h中。通常,只有疯狂的人会重新定义它,但这是可能的。一个例子:
#include <stdio.h>
#ifdef NULL
#undef NULL
#define NULL 1
#endif
void main()
{
if (NULL)
printf("NULL is true\n");
else
printf("NULL is false\n");
}
此代码将打印“NULL为true”。如果你不相信我,试试吧。您的编译器甚至可能不会警告您,您正在做一些奇怪的事情。
答案 6 :(得分:4)
是的,if(!p)
有效并且可以正常工作。
一个值为0的整数常量表达式,或强制转换为void *的表达式,称为空指针常量。如果将空指针常量转换为指针类型,则保证生成的指针(称为空指针)将不相等的值与指向任何对象或函数的指针进行比较。
https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p3
这意味着(void*)0
是空指针。这也意味着,如果p
是指针,则p==0
等效于p==(void*)0
。
这还意味着,如果p
不是非空指针,那么p==(void*)0
的值将为0
。
到目前为止,太好了。
将空指针转换为另一种指针类型会产生该类型的空指针。任何两个空指针应比较相等。
http://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p4
请注意“任何两个空指针都应相等。” 这意味着,如果p
是空指针,则p==0
的值将为true,因为{{ 1}}将提升为空指针0
。这也意味着非空指针不能等于空指针。
让我们看一下求反运算符。
逻辑否定运算符的结果!如果其操作数的值比较不等于0,则为0;如果其操作数的值比较等于0,则为1。结果的类型为int。表达式!E等效于(0 == E)。
http://port70.net/~nsz/c/c11/n1570.html#6.5.3.3p5
这告诉我们(void*)0
在定义上与!p
相同,与上述p==0
相同。
考虑到所有空指针都相等的事实,这意味着p==(void*)0
仅在p==(void*)0
为空指针时才为true,而在p
为空指针时只能为false。不是空指针。
是的,p
是检查if(!p)
是否为空指针的一种绝对安全的方法。
答案 7 :(得分:2)
NULL
被定义为一个常量指针,可以保证指向内存中无用/不存在的位置。 NULL
的大多数实现都是((void *)0)
,但并非必须如此。
答案 8 :(得分:2)
我只是简单地向您推荐C-FAQ的Question 5.3。它回答了这个问题。
答案 9 :(得分:2)
宏NULL在
(和其他标头)中定义为空指针常量;
值为 0 的整数常量表达式,或将其转换为类型的表达式 void *,称为空指针常量。
if(expression)语句
if(expression)语句else语句
在两种形式中,如果表达式比较不等于0,则执行第一个子语句。 在else形式中,如果表达式比较等于,则执行第二个子语句 §6.8.4.1语言133 ISO / IEC 9899:TC3委员会草案-2007年9月7日WG14 / N1256 到0。如果通过标签到达第一个子陈述,则第二个子陈述不 被执行。
因此,是的,如果编译器符合ISO C99,则可以假定以下语句将始终执行。
if (!NULL) { statement; }
以上引文来自ISO / IEC 9899:1999(C99)。您可以阅读here。
答案 10 :(得分:2)
是的
C标准6.3.2.3
整数常量表达式,其值为0,或者这样的整数 转换为void *类型的表达式称为空指针 如果将空指针常量转换为指针类型, 结果指针(称为空指针)可以保证进行比较 不等于指向任何对象或函数的指针。
和6.3.2.6
任何指针类型都可以转换为整数类型。除了作为 先前指定的结果是实现定义的。如果 结果不能以整数类型表示,行为 未定义。结果不必在值的范围内 任何整数类型。
-
将任何标量值转换为_Bool时,如果将 值比较等于0;否则,结果为1
答案 11 :(得分:0)
是的,主要是。
首先,NULL是一个typedef。我可以通过在先前包含的标题中说出来,让你彻底搞砸了
#define NULL 1
这可能没有多大意义,但是从什么时候开始其他人的代码才有意义? :)
此外,虽然它可能在语法上是安全的,但它在语义上并不正确。 NULL表示“无”,既不是true或false,也不是布尔值或int或字符串。它意味着“无所作为的象征”。因此,测试NULL更像是一个哲学问题:如果树落在森林中,if(listener)
,它是否发出声音?
帮助每个人,并明确对NULL进行测试。
答案 12 :(得分:0)
根据我的说法,假设并非总是安全的。由于可以根据程序中包含的标题来重新定义它。但是根据标准,可以保证空指针常量不指向任何实际对象,并且类型为void *
。
在我们的例子中,声明void *somePtr = NULL
也可以是void *somePtr = 0
,其中0
为空指针。
“一个值为0的整数常量表达式,或者将其转换为类型void *的表达式称为空指针常量。如果将空指针常量转换为指针类型,则保证生成的指针(称为空指针)将不等于指向任何对象或函数的指针。” https://www.geeksforgeeks.org/few-bytes-on-null-pointer-in-c/
这仅表示在该特定点评估*somePtr
可能会导致错误。
关于NULL指针常量的另一参考可以是第944 A.3页的https://www.gnu.org/software/libc/manual/pdf/libc.pdf
答案 13 :(得分:-3)
* NULL始终以0x00L为目标。你可以认为这是假的,但一定要经常做一个明确的检查。