我一直认为只需简单地if(p != NULL){..}
完成这项工作。但是读完之后了这个 Stack Overflow question之后,似乎没有。
那么,在吸收了关于NULL 指针可以具有非零值的问题的所有讨论之后,检查 NULL 指针的规范方法是什么?
我一直认为只需简单地if(p != NULL){..}
完成这项工作。但是读完之后了这个 Stack Overflow question之后,似乎没有。
那么,在吸收了关于NULL 指针可以具有非零值的问题的所有讨论之后,检查 NULL 指针的规范方法是什么?
我总是简单地认为 if(p != NULL){..} 会完成这项工作。
它会。
首先,要 100% 清楚,这里的C 和 C++没有区别。其次,您引用的 Stack Overflow 问题并没有谈论空指针。它引入了无效指针;至少就标准而言,仅通过尝试比较它们就会导致未定义的行为的指针。一般来说,没有办法测试指针是否有效。
最后,有三种普遍的方法来检查空指针:
if ( p != NULL ) ...
if ( p != 0 ) ...
if ( p ) ...
无论机器上的空指针表示如何,所有工作都有效。而且,所有这些都以某种方式具有误导性;你选择哪一个是选择最不坏的问题。形式上,前两个对于编译器是相同的;将常量NULL
or0
转换为 类型的空指针p
,并将转换结果与 进行比较p
。无论空指针的表示形式如何。
第三个略有不同:p
被隐式转换为bool
. 但是隐式转换被定义为 的结果p
!= 0
,所以你最终得到了同样的结果。(这意味着使用第三种样式确实没有有效的论据——它用隐式转换混淆,没有任何抵消的好处。)
您更喜欢前两个中的哪一个很大程度上取决于风格,可能部分取决于您在其他地方的编程风格:根据所涉及的习语,其中一个谎言会比另一个更麻烦。如果只是比较的问题,我想大多数人会喜欢NULL
,但在类似f( NULL )
的情况下,将选择的重载是f( int )
,而不是带有指针的重载。同样,如果f
是一个函数模板,f( NULL )
将在int
. (当然,一些编译器,比如 g++,如果NULL
在非指针上下文中使用会产生警告;如果你使用 g++,你真的应该使用NULL
.)
当然,在C++11中,首选的习惯用法是:
if ( p != nullptr ) ...
,这避免了其他解决方案的大部分问题。(但它不是 C 兼容的:-)。)
编译器必须提供一致的类型系统,并提供一组标准转换。整数值 0 和 NULL 指针都不需要由全零位表示,但编译器必须注意将输入文件中的“0”标记转换为整数零的正确表示,并转换为指针类型必须从整数转换为指针表示。
这意味着
void *p;
memset(&p, 0, sizeof p);
if(p) { ... }
不能保证在所有目标系统上都表现相同,因为您在此处对位模式做出假设。
例如,我有一个没有内存保护的嵌入式平台,并将中断向量保持在地址 0,因此按照惯例,整数和指针在转换时与 0x2000000 进行异或运算,从而使 (void *)0 指向一个地址取消引用时会产生总线错误,但是使用if
语句测试指针将首先将其返回为整数表示,然后是全零。
空指针的实际表示在这里无关紧要。值为零的整数文字(包括0
的任何有效定义NULL
)可以转换为任何指针类型,给出一个空指针,无论实际表示形式如何。所以p != NULL
和都是非空指针的有效测试p != 0
。p
如果你写了一些扭曲的东西,你可能会遇到空指针的非零表示的问题p != reinterpret_cast<void*>(0)
,所以不要这样做。
尽管我刚刚注意到您的问题被标记为 C 和 C++。我的回答是指C++,其他语言可能不一样。您使用哪种语言?
显然你提到的线程是关于C++
。
在C
您的代码段中将始终有效。我喜欢更简单的if (p) { /* ... */ }
。
指针的表示与比较它们无关,因为 C 中的所有比较都是作为值而不是表示进行的。比较表示的唯一方法是可怕的,例如:
static const char ptr_rep[sizeof ptr] = { 0 };
if (!memcmp(&ptr, ptr_rep, sizeof ptr)) ...
Well, this question was asked and answered way back in 2011, but there is nullptr
in C++11. That's all I'm using currently.
You can read more from Stack Overflow and also from this article.
if(p != NULL)
是一种检查指针是否为 NULL 的安全且可移植的方法。
C11 标准的第 7.19 节描述了 stddef.h 中包含的定义,包括NULL
. 相关部分如下:
1头文件
<stddef.h>
定义了以下宏并声明了以下类型。一些也在其他标题中定义,如其各自的子条款中所述。...
3宏是
NULL
它扩展为实现定义的空指针常量;...
这仅说明NULL
是实现定义的。它并不是说它必须所有位都为 0。
此外,第 6.2.3.2p3 节定义了空指针和空指针常量:
值为 0 的整数常量表达式,或转换为 type 的此类表达式
void *
称为空指针常量。如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证与指向任何对象或函数的指针不相等。
虽然上述声明0
(当转换为指针时)都(void *)0
构成空指针常量,但这并不意味着结果指针的所有位都为 0。标准中还有其他几个示例将值从一种类型转换为另一个不一定意味着表示是相同的。
这也表明空指针常量将与任何对象或函数比较不相等。本节第 4 段还规定:
将空指针转换为另一种指针类型会产生该类型的空指针。任何两个空指针应该比较相等。
因此,如果p
是一个空指针,那么它必须比较等于任何空指针,包括NULL
,在这种情况下p != NULL
将评估为假。相反,如果p
指向一个对象或函数,那么它必须与任何空指针进行比较,在这种情况下p != NULL
将评估为真。
再次注意,这里没有任何关于空指针将具有什么表示的假设。