是否可以安全地假设NULL
在C语言中始终将其转换为false?
void *somePtr = NULL;
if (!somePtr) {
/* This will always be executed? */
}
还是应该明确检查其价值NULL
?
是否可以安全地假设NULL
在C语言中始终将其转换为false?
void *somePtr = NULL;
if (!somePtr) {
/* This will always be executed? */
}
还是应该明确检查其价值NULL
?
Answers:
是。NULL的计算结果为false,因为C认为任何非零值均为true,而任何零值为false。NULL本质上是zero
地址,在比较中会这样处理,我相信对于布尔值检查,它会提升为int值。我希望熟悉C的任何人都可以阅读您的代码,尽管我可能会明确进行检查。
在C和C ++编程中,保证两个空指针比较相等。ANSI C保证在与整数类型进行比较时,任何空指针都将等于0。此外,宏NULL被定义为空指针常量,即值0(作为整数类型或转换为指向void的指针),因此空指针将比较等于NULL。
承担任何责任永远都不安全。
显式检查还可以使您更清楚地了解要测试的内容。
“ C”语言可以追溯到(void *)0实际上是有效指针的时代。不久之前,8080和Z80微处理器在地址0处有一个中断向量。面对这样的体系结构选择,除了让头文件声明NULL值外,它什么也不能做。有一些编译器在那里,现在早已被人们遗忘,其中NULL不等于(void *)0(0xffff是下一个替代方案),因此为if()语句提供了不确定的行为。
C ++尽心尽力地结束了这一点,空指针可以从0赋值,并且可以针对0进行测试。
我的ISO / IEC 9899:TC3(委员会草案,2007年9月7日)副本:
6.3转换
1一些运算符会自动将操作数值从一种类型转换为另一种类型。
6.3.2.3指针
3值为0 [...]的整数常量表达式称为空指针常量。如果将空指针常量转换为指针类型,则保证生成的指针(称为空指针)将不相等的值与指向任何对象或函数的指针进行比较。
到目前为止,ptr!=0
对于每个非null来说都是true(1)ptr
,但是它仍然是开放的,如何比较两个null指针。
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
为空指针。是的,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
不是非null指针,p==(void*)0
则将求值为0
。
到现在为止还挺好。
将空指针转换为另一种指针类型将产生该类型的空指针。任何两个空指针应比较相等。
http://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p4
注意:“任何两个空指针都应相等。” 这意味着,如果p
为空指针,p==0
则将评估为true,因为0
将被提升为(void*)0
空指针。这也意味着非空指针不能等于空指针。
让我们看一下求反运算符。
逻辑否定运算符的结果!如果其操作数的值比较不等于0,则为0;如果其操作数的值比较等于0,则为1。结果的类型为int。表达式!E等效于(0 == E)。
http://port70.net/~nsz/c/c11/n1570.html#6.5.3.3p5
这告诉我们这!p
与p==0
定义相同,也p==(void*)0
与上述相同。
考虑到所有空指针都相等的事实,这意味着,p==(void*)0
如果p
为空指针,则只能求值为true;如果不是空指针,则只能求值为false p
。
所以,if(!p)
是一种检查是否p
为空指针的绝对安全的方法。
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”。如果您不相信我,请尝试一下。您的编译器甚至可能不会警告您您做的事情很奇怪。
是的,它:
C标准6.3.2.3
值为0的整数常量表达式或强制转换为void *的表达式称为空指针常量。如果将空指针常量转换为指针类型,则保证生成的指针称为空指针。比较不等于指向任何对象或函数的指针。
和6.3.2.6
任何指针类型都可以转换为整数类型。除非先前指定,否则结果是实现定义的。如果结果不能用整数类型表示,则行为未定义。结果不必在任何整数类型的值范围内。
--
当任何标量值转换为_Bool时,如果该值比较等于0,则结果为0;否则,结果为0。否则,结果为1
宏NULL在<stddef.h>(和其他标头)中定义为空指针常量;
值为0的整数常量表达式,或强制转换为void *类型的表达式,称为空指针常量。
示例定义:
#define NULL ((void*)0)
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)。您可以在这里阅读。
NULL
被定义为保证指向内存中无用/不存在位置的常量指针。的大多数实现NULL
是,((void *)0)
但并非必须如此。
据我说,假设并非总是安全的。由于可以根据程序中包含的标题来重新定义它。但是根据标准,可以保证空指针常量不指向任何实际对象并且具有类型void *
。
在我们的例子中,声明void *somePtr = NULL
也可以void *somePtr = 0
使用0
null指针。
“一个整数常量表达式,其值为0,或将这种表达式强制转换为void *类型,称为空指针常量。如果将空指针常量转换为指针类型,则可以保证生成的指针(称为空指针)与指向任何对象或函数的指针不相等。https://www.geeksforgeeks.org/few-bytes-on-null-pointer-in-c/
这仅表示*somePtr
在该特定点进行评估可能会导致错误。
关于空指针常量的另一个参考可以是第944 A.3页的https://www.gnu.org/software/libc/manual/pdf/libc.pdf
* NULL始终以0x00L为目标。您可以认为这是错误的,但要确保始终进行显式检查。