如何检查指针是否为空指针?

时间:2023-01-28 07:30:00

I always think simply if(p != NULL){..} will do the job. But after reading this Stack Overflow question, it seems not.

我总是简单地认为如果(p != NULL){..)可以做这个工作。但是在阅读了这个堆栈溢出问题之后,它似乎不是。

So what's the canonical way to check for NULL pointers after absorbing all discussion in that question which says NULL pointers can have non-zero value?

那么,在吸收了这个问题的所有讨论后,检查空指针是否有非零值的标准方法是什么呢?

7 个解决方案

#1


37  

I always think simply if(p != NULL){..} will do the job.

我总是简单地认为如果(p != NULL){..)可以做这个工作。

It will.

它将。

#2


23  

First, to be 100% clear, there is no difference between C and C++here. And second, the Stack Overflow question you cite doesn't talk about null pointers; it introduces invalid pointers; pointers which, at least as far as thestandard is concerned, cause undefined behavior just by trying tocompare them. There is no way to test in general whether a pointer isvalid.

首先,要百分百清楚,这里的C和c++没有区别。第二,你所引用的堆栈溢出问题并不涉及空指针;它介绍了无效的指针;指针,至少就标准而言,仅仅通过比较就会导致未定义的行为。一般来说,没有办法测试指针是否有效。

In the end, there are three widespread ways to check for a null pointer:

最后,有三种常见的检查空指针的方法:

if ( p != NULL ) ...if ( p != 0 ) ...if ( p ) ...

All work, regardless of the representation of a null pointer on themachine. And all, in some way or another, are misleading; which one youchoose is a question of choosing the least bad. Formally, the first twoare indentical for the compiler; the constant NULL or 0 is convertedto a null pointer of the type of p, and the results of the conversionare compared to p. Regardless of the representation of a nullpointer.

所有的工作,不管空指针在themachine上的表示是什么。所有这些,以某种方式,都具有误导性;你选择哪一个是选择最不坏的。正式地说,前两个对编译器来说是外延的;常量NULL或0被转换为p类型的空指针,并且转换的结果与p进行比较。

The third is slightly different: p is implicitly convertedto bool. But the implicit conversion is defined as the results of p!= 0, so you end up with the same thing. (Which means that there'sreally no valid argument for using the third style—it obfuscateswith an implicit conversion, without any offsetting benefit.)

第三个则稍有不同:p隐式地收敛于bool。但是隐式转换被定义为p的结果!结果是一样的。(这意味着使用第三种风格并没有有效的理由——它混淆了隐式转换,没有任何抵消的好处。)

Which one of the first two you prefer is largely a matter of style,perhaps partially dictated by your programming style elsewhere:depending on the idiom involved, one of the lies will be more bothersomethan the other. If it were only a question of comparison, I think mostpeople would favor NULL, but in something like f( NULL ), theoverload which will be chosen is f( int ), and not an overload with apointer. Similarly, if f is a function template, f( NULL ) willinstantiate the template on int. (Of course, some compilers, likeg++, will generate a warning if NULL is used in a non-pointer context;if you use g++, you really should use NULL.)

您喜欢的前两种语言中的哪一种主要是风格问题,可能部分取决于您在其他地方的编程风格:根据所涉及的习惯用法,其中一种谎言将比另一种更麻烦。如果只是比较的问题,我想大多数人会喜欢NULL,但是在f(NULL)之类的东西中,要选择的重载是f(int),而不是带apointer的重载。类似地,如果f是一个函数模板,那么f(NULL) willinstantiate在int上的模板(当然,一些编译器,如g++,如果在非指针上下文中使用NULL,将会生成一个警告;如果使用g++,那么实际上应该使用NULL。)

In C++11, of course, the preferred idiom is:

当然,在c++ 11中,首选的习语是:

if ( p != nullptr ) ...

, which avoids most of the problems with the other solutions. (But itis not C-compatible:-).)

,避免了其他解决方案的大部分问题。(但它不是C-compatible:-))。

#3


9  

The compiler must provide a consistent type system, and provide a set of standard conversions. Neither the integer value 0 nor the NULL pointer need to be represented by all-zero bits, but the compiler must take care of converting the "0" token in the input file to the correct representation for integer zero, and the cast to pointer type must convert from integer to pointer representation.

编译器必须提供一致的类型系统,并提供一组标准转换。无论是整数值0还是空指针需要由零位,但编译器必须照顾转换输入文件中的“0”牌的正确表示整数0,和演员指针类型必须从整数转换为指针表示。

The implication of this is that

这意味着

void *p;memset(&p, 0, sizeof p);if(p) { ... }

is not guaranteed to behave the same on all target systems, as you are making an assumption about the bit pattern here.

不能保证在所有目标系统上都有相同的行为,因为你在这里假设了比特模式。

As an example, I have an embedded platform that has no memory protection, and keeps the interrupt vectors at address 0, so by convention, integers and pointers are XORed with 0x2000000 when converted, which leaves (void *)0 pointing at an address that generates a bus error when dereferenced, however testing the pointer with an if statement will return it to integer representation first, which is then all-zeros.

作为一个例子,我有一个嵌入式平台,没有内存保护,并保持中断向量地址0,所以按照惯例,整数和指针与0 xor x2000000转换时,叶子(void *)0指着一个地址时,生成一个总线错误的引用时,然而测试指针一个if语句会返回第一个整数表示,然后全0。

#4


6  

The actual representation of a null pointer is irrelevant here. An integer literal with value zero (including 0 and any valid definition of NULL) can be converted to any pointer type, giving a null pointer, whatever the actual representation. So p != NULL, p != 0 and p are all valid tests for a non-null pointer.

空指针的实际表示在这里是不相关的。具有值为0的整型文字(包括0和任何有效的NULL定义)可以转换为任何指针类型,给出一个空指针,无论实际的表示是什么。所以p != NULL, p != 0和p都是对非空指针的有效测试。

You might run into problems with non-zero representations of the null pointer if you wrote something twisted like p != reinterpret_cast<void*>(0), so don't do that.

如果您编写了像p != reviewt_cast (0)这样的扭曲,那么您可能会遇到null指针的非零表示的问题,所以不要这样做。 *>

Although I've just noticed that your question is tagged C as well as C++. My answer refers to C++, and other languages may be different. Which language are you using?

虽然我刚刚注意到您的问题被标记为C和c++。我的答案是c++,其他语言可能不同。你在用什么语言?

#5


4  

Apparently the thread you refer is about C++.

显然,您提到的线程是关于c++的。

In C your snippet will always work. I like the simpler if (p) { /* ... */ }.

在C语言中,您的代码片段将始终有效。我喜欢简单一点的if (p){/*…* / }。

#6


2  

The representation of pointers is irrelevant to comparing them, since all comparisons in C take place as values not representations. The only way to compare the representation would be something hideous like:

指针的表示与比较它们无关,因为C中的所有比较都是作为值而不是表示进行的。唯一的对比方式是一些可怕的东西,比如:

static const char ptr_rep[sizeof ptr] = { 0 };if (!memcmp(&ptr, ptr_rep, sizeof ptr)) ...

#7


1  

Well, this question was asked and answered way back in 2011, but there is nullptrin C++11. That's all I'm using currently.

这个问题早在2011年就有人提出并回答了,但是有nullptrin c++ 11。这就是我目前使用的所有东西。

You can read more from Stack Overflow and also from this article.

您可以从Stack Overflow和本文获得更多信息。

#1


37  

I always think simply if(p != NULL){..} will do the job.

我总是简单地认为如果(p != NULL){..)可以做这个工作。

It will.

它将。

#2


23  

First, to be 100% clear, there is no difference between C and C++here. And second, the Stack Overflow question you cite doesn't talk about null pointers; it introduces invalid pointers; pointers which, at least as far as thestandard is concerned, cause undefined behavior just by trying tocompare them. There is no way to test in general whether a pointer isvalid.

首先,要百分百清楚,这里的C和c++没有区别。第二,你所引用的堆栈溢出问题并不涉及空指针;它介绍了无效的指针;指针,至少就标准而言,仅仅通过比较就会导致未定义的行为。一般来说,没有办法测试指针是否有效。

In the end, there are three widespread ways to check for a null pointer:

最后,有三种常见的检查空指针的方法:

if ( p != NULL ) ...if ( p != 0 ) ...if ( p ) ...

All work, regardless of the representation of a null pointer on themachine. And all, in some way or another, are misleading; which one youchoose is a question of choosing the least bad. Formally, the first twoare indentical for the compiler; the constant NULL or 0 is convertedto a null pointer of the type of p, and the results of the conversionare compared to p. Regardless of the representation of a nullpointer.

所有的工作,不管空指针在themachine上的表示是什么。所有这些,以某种方式,都具有误导性;你选择哪一个是选择最不坏的。正式地说,前两个对编译器来说是外延的;常量NULL或0被转换为p类型的空指针,并且转换的结果与p进行比较。

The third is slightly different: p is implicitly convertedto bool. But the implicit conversion is defined as the results of p!= 0, so you end up with the same thing. (Which means that there'sreally no valid argument for using the third style—it obfuscateswith an implicit conversion, without any offsetting benefit.)

第三个则稍有不同:p隐式地收敛于bool。但是隐式转换被定义为p的结果!结果是一样的。(这意味着使用第三种风格并没有有效的理由——它混淆了隐式转换,没有任何抵消的好处。)

Which one of the first two you prefer is largely a matter of style,perhaps partially dictated by your programming style elsewhere:depending on the idiom involved, one of the lies will be more bothersomethan the other. If it were only a question of comparison, I think mostpeople would favor NULL, but in something like f( NULL ), theoverload which will be chosen is f( int ), and not an overload with apointer. Similarly, if f is a function template, f( NULL ) willinstantiate the template on int. (Of course, some compilers, likeg++, will generate a warning if NULL is used in a non-pointer context;if you use g++, you really should use NULL.)

您喜欢的前两种语言中的哪一种主要是风格问题,可能部分取决于您在其他地方的编程风格:根据所涉及的习惯用法,其中一种谎言将比另一种更麻烦。如果只是比较的问题,我想大多数人会喜欢NULL,但是在f(NULL)之类的东西中,要选择的重载是f(int),而不是带apointer的重载。类似地,如果f是一个函数模板,那么f(NULL) willinstantiate在int上的模板(当然,一些编译器,如g++,如果在非指针上下文中使用NULL,将会生成一个警告;如果使用g++,那么实际上应该使用NULL。)

In C++11, of course, the preferred idiom is:

当然,在c++ 11中,首选的习语是:

if ( p != nullptr ) ...

, which avoids most of the problems with the other solutions. (But itis not C-compatible:-).)

,避免了其他解决方案的大部分问题。(但它不是C-compatible:-))。

#3


9  

The compiler must provide a consistent type system, and provide a set of standard conversions. Neither the integer value 0 nor the NULL pointer need to be represented by all-zero bits, but the compiler must take care of converting the "0" token in the input file to the correct representation for integer zero, and the cast to pointer type must convert from integer to pointer representation.

编译器必须提供一致的类型系统,并提供一组标准转换。无论是整数值0还是空指针需要由零位,但编译器必须照顾转换输入文件中的“0”牌的正确表示整数0,和演员指针类型必须从整数转换为指针表示。

The implication of this is that

这意味着

void *p;memset(&p, 0, sizeof p);if(p) { ... }

is not guaranteed to behave the same on all target systems, as you are making an assumption about the bit pattern here.

不能保证在所有目标系统上都有相同的行为,因为你在这里假设了比特模式。

As an example, I have an embedded platform that has no memory protection, and keeps the interrupt vectors at address 0, so by convention, integers and pointers are XORed with 0x2000000 when converted, which leaves (void *)0 pointing at an address that generates a bus error when dereferenced, however testing the pointer with an if statement will return it to integer representation first, which is then all-zeros.

作为一个例子,我有一个嵌入式平台,没有内存保护,并保持中断向量地址0,所以按照惯例,整数和指针与0 xor x2000000转换时,叶子(void *)0指着一个地址时,生成一个总线错误的引用时,然而测试指针一个if语句会返回第一个整数表示,然后全0。

#4


6  

The actual representation of a null pointer is irrelevant here. An integer literal with value zero (including 0 and any valid definition of NULL) can be converted to any pointer type, giving a null pointer, whatever the actual representation. So p != NULL, p != 0 and p are all valid tests for a non-null pointer.

空指针的实际表示在这里是不相关的。具有值为0的整型文字(包括0和任何有效的NULL定义)可以转换为任何指针类型,给出一个空指针,无论实际的表示是什么。所以p != NULL, p != 0和p都是对非空指针的有效测试。

You might run into problems with non-zero representations of the null pointer if you wrote something twisted like p != reinterpret_cast<void*>(0), so don't do that.

如果您编写了像p != reviewt_cast (0)这样的扭曲,那么您可能会遇到null指针的非零表示的问题,所以不要这样做。 *>

Although I've just noticed that your question is tagged C as well as C++. My answer refers to C++, and other languages may be different. Which language are you using?

虽然我刚刚注意到您的问题被标记为C和c++。我的答案是c++,其他语言可能不同。你在用什么语言?

#5


4  

Apparently the thread you refer is about C++.

显然,您提到的线程是关于c++的。

In C your snippet will always work. I like the simpler if (p) { /* ... */ }.

在C语言中,您的代码片段将始终有效。我喜欢简单一点的if (p){/*…* / }。

#6


2  

The representation of pointers is irrelevant to comparing them, since all comparisons in C take place as values not representations. The only way to compare the representation would be something hideous like:

指针的表示与比较它们无关,因为C中的所有比较都是作为值而不是表示进行的。唯一的对比方式是一些可怕的东西,比如:

static const char ptr_rep[sizeof ptr] = { 0 };if (!memcmp(&ptr, ptr_rep, sizeof ptr)) ...

#7


1  

Well, this question was asked and answered way back in 2011, but there is nullptrin C++11. That's all I'm using currently.

这个问题早在2011年就有人提出并回答了,但是有nullptrin c++ 11。这就是我目前使用的所有东西。

You can read more from Stack Overflow and also from this article.

您可以从Stack Overflow和本文获得更多信息。