68

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

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?

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
cpuer
  • 7,413
  • 14
  • 35
  • 39
  • 4
    That's not c...it's a c++ thread... personally, I'd go with: `if(p) {...}` – forsvarir May 31 '11 at 09:54
  • 4
    You are worrying too much - your code is fine, even in C++. That discussion was between some language lawyers - it's kind of the "how many angels can dance on a head of pin" stuff. –  May 31 '11 at 09:55
  • @forsvarir ,when will `if(p)` be different from `if(p != NULL)`? – cpuer May 31 '11 at 09:56
  • @cpuer: when you haven't included a header file that defines NULL, one will compile, the other wont... – forsvarir May 31 '11 at 09:57
  • @forsvarir ,OK,in that case ,it's different :) But you didn't mention what's discussed in that thread,which says sometimes NULL pointers can have non-zero value...In that case,both `if(p)` and `if(p!=NULL)` will fail,I think. – cpuer May 31 '11 at 09:59
  • @cpuer The internal rep of a NULL pointer could in theory have a non-zero value (in fact they don't), but this is nothing for you to worry about. –  May 31 '11 at 10:00
  • @Neil Butterworth ,if the internal rep of NULL pointer is not a non-zero,both `if(p)` and `if(p!=NULL)` will fail,I've no reason not to worry about that. – cpuer May 31 '11 at 10:01
  • 4
    @cpuer No they won't because they are not using the internal rep - your code is fine! It's the way ALL C code and ALL C++ code is written - that thread was an abstract intellectual discussion about the wording of the C++ standard. You get a lot of that on the C++ tags. –  May 31 '11 at 10:03
  • @Neil Butterworth ,two different threads on the same topic have two different answer,but I decide to stick to my own one:) – cpuer May 31 '11 at 10:06
  • 2
    @cpuer: in C even `if (p != 0)` will "work" when the internal representation is not all bits zero. – pmg May 31 '11 at 10:07
  • Ack! I think the point is that even if internally NULL is not 0, a null pointer will always have the value of NULL. Just don't `#define NULL p`, and keep smiling. – tjm May 31 '11 at 10:10
  • @pmg: and in C++ too. My attempt to explain it: in both languages, `NULL` either *is* a null pointer, or else it *converts* to a null pointer (in C it's implementation-dependent which, in C++ it's always the latter). And in both languages null pointers compare equal. It's completely irrelevant whether null pointers have all-bits-zero or not, `0` (or any other integer constant expression with value 0) and `NULL` still convert to null pointers, not (necessarily) pointers with all bits zero. – Steve Jessop May 31 '11 at 10:58
  • [This thread](http://stackoverflow.com/questions/5142251/redefining-null) discusses whether NULL can be defined to have a non-zero value or not. C is different from C++, because in C++ NULL is 0, end of story. In C, NULL is something magical that appears when you typecast the integer 0 into a pointer. – Lundin May 31 '11 at 11:06
  • 1
    @cpuer Both C and C++ are (almost) identical in this respect. You cannot directly compare a pointer with an `int`. The `int` must first be converted into a pointer. If (and only if) the `int` is an integral constant expression evaluating to 0, there is an implicit conversion, which results in a null pointer. (In C, there is one other possibility.) The results of that conversion will be whatever the implementation requires. And if you write simply `if (p)`, the language defines this to be the exact equivalent of `if (p != 0)`. – James Kanze May 31 '11 at 12:41
  • 1
    @Lundin The requirements for the definition of `NULL` are identical, word for word, in the C and the C++ standard. Both require that it be defined as a "null pointer constant". Traditionally, `0`, but any "constant integral expression evaluating to 0" is allowed; in C, the definition of "null pointer constant" also allows this to be cast to `void*`, but that really doesn't change anything. In both cases, the conversion of a null pointer constant into a null pointer is compiler magic. – James Kanze May 31 '11 at 17:30
  • 3
    To keep the issues clearer: `NULL` is a macro, defined in `` (and some other headers). `NULL` is *not* a null pointer; it is required to be defined as a "null pointer constant" (which in C++, cannot be a pointer, and in C, traditionally is not a pointer). There are three separate concepts which must be dealt with: `NULL`, a null pointer, and a null pointer constant. And how a null pointer is physically represented (its bit pattern) is completely independent of the other two. – James Kanze May 31 '11 at 17:34
  • I've removed [tag:c++] because in C++, the situation is completely different: https://stackoverflow.com/questions/17772103/can-i-use-if-pointer-instead-of-if-pointer-null – ivan_pozdeev May 17 '18 at 14:05
  • @cpuer would you consider accept an answer? Probably [this one](https://stackoverflow.com/a/6185861/2989289) – artu-hnrq Mar 01 '20 at 23:16

9 Answers9

92

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

It will.

cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • @cpuer I know little C++ but from the one C++ book I read (C++ Primer Plus) I *still* think it will work. As long as `NULL` is defined to something non-braindead. – cnicutar May 31 '11 at 10:04
  • 4
    This style is considered better than if(p), because the expression inside an if-statement should be a boolean one, and "p" in this case is a pointer, not a bool. It is considered safer and better practice to explicitly check against zero with == or != (MISRA-C:2004 13.2). – Lundin May 31 '11 at 11:08
  • 4
    @Lundin: the condition inside an if statement only needs to be convertible to a boolean; in that context `p` is equivalent to `p != NULL`, and it's purely a matter of aesthetics which you choose. Neither is safer or "better practice" than the other. – Mike Seymour May 31 '11 at 14:27
  • @Mike Seymour For historical reasons, the language (be it C or C++) has a lot of implicit conversions. For readability, it's generally better to avoid them. If you know that `if (p)` actually means `if (p != NULL)`, why hide this fact from the reader. – James Kanze May 31 '11 at 17:36
  • @James: As I said, it's a matter of aesthetics. I find `if (p)` slightly clearer as it doesn't introduce unnecessary noise; others find your preference slightly clearer as it's more explicit; and noone with any experience at all will find either form unclear. There's certainly no reason to describe either as "generally better" or "safer and better practice" unless your business is to sell coding standards. – Mike Seymour May 31 '11 at 18:26
  • @Mike I think MISRA considered it safer as it is more readable. If you compare p against NULL explicitly, it is obvious to the reader what you are doing. For example, consider some code like `if(*(ptr+1))` and compare it to `if(*(ptr+1) == NULL)`. Only the latter case makes it obvious that the type of ptr is a pointer-to-pointer and that we are interested in its address. – Lundin May 31 '11 at 21:37
  • 3
    @Mike Seymour I'm rather against `if (p)` because I still have to stop and think about it. As you say, it's probably a question of experience; I've only been using C and C++ for 30 years, so no doubt it will come to me in time. (Seriously, it may be a question of another experience; I used Pascal and Modula-2 extensively before starting with C, and had already grown used to strict typing. I've never felt comfortable with C's looseness here, with implicit conversions all over the place.) – James Kanze Jun 01 '11 at 07:56
  • 2
    @James: OK, I was wrong to say that experienced programmers won't find either form unclear. That surprises me, but I can't argue with evidence. – Mike Seymour Jun 01 '11 at 09:55
  • 1
    @Lundin: `*p == NULL` will still compile (certainly in C++03, and in C depending on the definition of `NULL`) even if `p` isn't a pointer to a pointer, in which case the extra noise is then misleading as well as unnecessary. But, as I keep saying, it's really not worth arguing about minor aesthetic points unless (like MISRA) you're in the business of selling coding standards. – Mike Seymour Jun 01 '11 at 09:58
  • @Mike It depends on your experience, I suppose. The `if (p)` idiom is widely enough used that I'm sure at least some programmers read it without problems. All of the places I've worked have insisted on `if (p != NULL)` in their coding guidelines, so even in C or C++, I'm not that used to seeing it. – James Kanze Jun 01 '11 at 10:40
  • @James: I might say that that's an argument against overly prescriptive coding standards, not an argument in favour of whichever coding standards you happen to have had imposed on you, but we're already getting very off-topic here. – Mike Seymour Jun 01 '11 at 10:52
  • @Mike `*p == NULL` is likely to give a warning though, if NULL was defined as (void*)0, as is most often the case. – Lundin Jun 02 '11 at 19:38
  • 2
    @Lundin: In C, yes. In C++, `(void*)0` is not a valid definition for `NULL`; it must be convertible to any pointer type, and C++ does not allow implicit conversions from `void*` to other pointer types. So `NULL` must be defined as a zero-valued literal of integer type, and comparing that to another numeric type will not give a warning. (C++0x will sort this out by introducing `nullptr`, of a type that's convertible to pointer types but not numeric types, but until then we just have to muddle through as best we can). – Mike Seymour Jun 03 '11 at 10:37
  • can we also say c!=nullptr? – Mona Jalal Jun 02 '17 at 03:05
  • When I do this, it thinks `NULL` is of type `long`? I have `#define NULL __null` – Aaron Franke Nov 28 '19 at 09:47
41

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 the standard is concerned, cause undefined behavior just by trying to compare them. There is no way to test in general whether a pointer is valid.

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 the machine. And all, in some way or another, are misleading; which one you choose is a question of choosing the least bad. Formally, the first two are indentical for the compiler; the constant NULL or 0 is converted to a null pointer of the type of p, and the results of the conversion are compared to p. Regardless of the representation of a null pointer.

The third is slightly different: p is implicitly converted to 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's really no valid argument for using the third style—it obfuscates with an implicit conversion, without any offsetting benefit.)

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 bothersome than the other. If it were only a question of comparison, I think most people would favor NULL, but in something like f( NULL ), the overload which will be chosen is f( int ), and not an overload with a pointer. Similarly, if f is a function template, f( NULL ) will instantiate the template on int. (Of course, some compilers, like g++, will generate a warning if NULL is used in a non-pointer context; if you use g++, you really should use NULL.)

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

if ( p != nullptr ) ...

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • @James Kanze,I don't think there's such implicit conversion as `void *p = main;if(p == 0x4004e3)printf("1\n");` prints `1`(here `0x4004e3` should be replaced with the actual address of `main`). That said,a pointer can be used to compare with an integer,and no conversion is involved. – compile-fan May 31 '11 at 13:30
  • @compile-fan Of course there's no such implicit conversion. `main` has, in fact, a very special type; I don't think that there's any way to get its address, at least in C++, and if you could, there's nothing you could do with it. But in general, there's no implicit conversion of one pointer type to another, except for the special case that any data pointer can be converted to a `void*` with acceptable cv qualifiers. If the code you cite compiles, the compiler is broken. – James Kanze May 31 '11 at 13:54
  • @James Kanze ,it compiles in C,I think should also compile in c++.You can just put the code into the body of `int main(int argc,char *argv[]){...}`. – compile-fan May 31 '11 at 13:58
  • Warning is given,but it compiles anyway. – compile-fan May 31 '11 at 14:12
  • 2
    @vompile-fan It is not legal C, nor legal C++. In C, you can take the address of `main`, provided a declaration of `main` is visible; in C++, I'm not sure. In neither language, however, is there an implicit conversion of a pointer to function to `void*`, and in neither can you compare a pointer with an integer, other than a null pointer constant. The first is often accepted (with or without warning), for historical reasons; a compiler which accepts the second, however, is seriously broken. – James Kanze May 31 '11 at 14:21
  • @James Kanze,what do you think of `int* p_1=(int*)569;`(assignment of non null-pointer-constants),is it legal ? – compile-fan May 31 '11 at 15:57
  • @compile-fan It's implementation defined. In C++, that would be a `reinterpret_cast`, which the standard says is implementation defined," but "is intended to be unsurprising to those who know the addressing structure of the underlying machine." – James Kanze May 31 '11 at 17:45
  • @James Kanze,for those machines that have non-zero null pointer representations,for example,uses `0x567` as the internal representation,`if(p)` will be the same as `if(p != 0x567)`,but the later is,like you said,**implementation defined**,right? And I can even say that in this case any valid object won't lie at address `0x567`,is that right? – cpuer Jun 01 '11 at 01:21
  • I like it how C takes a super mega trivial job (like checking for null) and makes it overly complicated.... :) – Gabriel Sep 16 '19 at 08:27
  • @Antikythera You can thank the people who wrote bad C code assuming `NULL` was zero. The C committee had to accommodate that unsupported assumption. See http://c-faq.com/null/machexamp.html – Andrew Henle Feb 13 '20 at 21:30
10

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.

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.

Simon Richter
  • 28,572
  • 1
  • 42
  • 64
  • OK,so let's regard null pointer const(`0`,`void *0`,`NULL`) as a special case,what about when comparing a pointer with a non-zero integer?Please see my updated question above:) – compile-fan May 31 '11 at 16:05
  • You still need to convert either value so it can be compared, there is no direct comparison operator. In my compiler that means, that either the left or the right hand side is XOR'd before comparison, which makes the entire thing consistent again. – Simon Richter May 31 '11 at 17:09
  • That's sensible, but it's not required. Assigning `0` to an `int`, then explicitly converting that `int` to a pointer is allowed to give different results than the implicit conversion of the constant `0` to a pointer. – James Kanze May 31 '11 at 17:38
  • @James Kanze As someone who thinks of the sentence "A diagnostic is not required" as a challenge, I am intrigued by the idea. There goes tonight's Minecraft session. – Simon Richter May 31 '11 at 18:02
7

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.

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.

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?

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • what about when comparing a pointer with a non-zero integer?Please see my updated question above:) – compile-fan May 31 '11 at 16:06
  • @compile-fan: comparison with a non-zero integer shouldn't compile, since a pointer can't be compared directly to an integer, and only a zero-valued integer literal can be implicitly converted to a (null) pointer. You can force it to compile with a dodgy cast, but then the behaviour is undefined. (Again, I'm answering for C++, but I'm fairly sure the answer is the same in C). – Mike Seymour May 31 '11 at 16:12
6

Apparently the thread you refer is about C++.

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

pmg
  • 106,608
  • 13
  • 126
  • 198
  • @pmg,I added c++ tag,so my purpose is to conclude a way to check null pointers that'll work for both c/c++ – cpuer May 31 '11 at 09:57
  • 1
    @cpuer Do what you are doing! Really, there is no problem here! –  May 31 '11 at 10:01
  • Checking for null pointers is nothing compared to the problems you will face with multi-language source files. I suggest you stick to one language per source file. ;) – pmg May 31 '11 at 10:05
  • @pmg,sure,I'll never mix two languages in a single file:) – cpuer May 31 '11 at 10:07
  • So, when it's C, use `if (p)` (`if (p != NULL)`, `if (p != 0)`) or `if (!p)` (`if (p == NULL)`, `if (p == 0)`); when it's C++, use the C++ idiom (I have no idea what it is). – pmg May 31 '11 at 10:10
  • @pmg It's the same. There's no difference between C and C++ here. (Including the fact that different people disagree as to which style is better.) – James Kanze May 31 '11 at 17:40
3

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:

static const char ptr_rep[sizeof ptr] = { 0 };
if (!memcmp(&ptr, ptr_rep, sizeof ptr)) ...
R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • @R..,maybe you can lay down more words on this:) It seems to me should be `!memcmp(ptr, ptr_rep, sizeof ptr)` at least... – compile-fan May 31 '11 at 13:40
  • 1
    No, my version is correct. You want to compare the representation of `ptr`, not the representation of what it points to, so you need the address of the variable `ptr`. – R.. GitHub STOP HELPING ICE May 31 '11 at 13:41
  • @R..,what about when you compare a pointer with a non-zero integer, does implicit convertion happen? Or is it like @James Kanze said,a compiler that accepts compare a pointer with an integer, other than a null pointer constant,is seriously broken ? – compile-fan May 31 '11 at 15:42
  • Pointers cannot be compared against integers without an explicit cast, which has implementation-defined behavior. The *integer constant expression* zero (but not non-integer-constant-expression zeros) just happens to be special; the integer constant expression 0 becomes a null pointer when needed. An interesting consequence is that `void *dummy = sizeof(short)-2;` makes a compile-time assertion that `sizeof(short)==2` (it's only valid C if the expression evaluates to 0). – R.. GitHub STOP HELPING ICE May 31 '11 at 17:20
  • @R..,for those machines that have non-zero null pointer representations,for example,uses `0x567` as the internal representation,`if(p)` will be the same as `if(p != 0x567)`,but the later is,like you said,**implementation defined**,right? And I can even say that in this case any valid object won't lie at address `0x567`,is that right? – cpuer Jun 01 '11 at 01:30
  • 1
    `if (p != 0x567)` is not valid C and will not compile. What you mean is `if (p != (void *)0x567)`, but this has implementation-defined behavior and is not necessarily the same as comparing the representation. – R.. GitHub STOP HELPING ICE Jun 01 '11 at 13:30
2

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

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

Community
  • 1
  • 1
JohnJohn
  • 325
  • 1
  • 6
  • 17
  • 1
    Question did not exclude C++11. You can learn more from the above two links. – JohnJohn Feb 20 '15 at 11:55
  • 1
    I don't know if you are just trying to piss people off or anything. The links I provided gives plenty of explanation. There's no use - and would be bad- to be copy-pasting the contents of the links here. As his question has already been answered in stackoverlow. I provided the solution by saying 'you can use nullptr in C++11' while giving the links for elaboration. If I wrote `if(p == nullptr) {}`. in the answer as well, it would just be an insult to the OP. `nullptr` **IS** the canonical way as included by the official C++ standard. Your lack of decency will not waste any more of my time. – JohnJohn Feb 21 '15 at 16:57
1

if(p != NULL) is a safe and portable way to check if a pointer is NULL.

Section 7.19 of the C11 standard describes definitions contained in stddef.h, including NULL. The relevant parts are as follows:

1 The header <stddef.h> defines the following macros and declares the following types. Some are also defined in other headers, as noted in their respective subclauses.

...

3 The macros are

NULL

which expands to an implementation-defined null pointer constant; ...

This only states that NULL is implementation defined. It doesn't say that it has to have all bits 0.

Also, section 6.2.3.2p3 defines null pointers and null pointer constants:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

While the above states that both 0 (when converted to a pointer) and (void *)0 constitute a null pointer constant, it doesn't imply that the resulting pointer has all bits 0. There are several other examples in the standard where converting a value from one type to another doesn't necessarily means the representation is the same.

This also states that a null pointer constant will compare unequal to any object or function. Paragraph 4 of this section also states:

Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.

So that if p is a null pointer then it must compare equal to any null pointer including NULL, in which case p != NULL would evaluate to false. Conversely, if p points to an object or function then it must compare unequal to any null pointer in which case p != NULL would evaluate to true.

Again, note that nothing here makes any assumptions about what representation a null pointer would have.

dbush
  • 205,898
  • 23
  • 218
  • 273
0

Nowadays, you can use the is null and is not null constructs. These read clearly.

if (ptr is null)
    throw new ArgumentNullException();

if (ptr is not null)
{
    // do something
}
IamIC
  • 17,747
  • 20
  • 91
  • 154