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