NULL vs 0

Started by
43 comments, last by wqking 11 years, 4 months ago
[[size=2]forked from Problems with my custom linked list class]

In another thread, I gave this advice:
Don't compare to 0, compare to NULL (or if using C++11, compare to nullptr). It describes your intent better.[/quote]

Another forummer responded,
...I always thought the same thing you just said there. Though I posted a basic Linked List code couple weeks ago and was using NULL instead of 0 and someone who said he was a TA at a University kept saying that I should not be using NULL in C++, use 0. Good to know that what I learned to use NULL still seems to be right. Also I do use nullptr when I can but the University Compilers don't support C++11 yet.[/quote]

So I'd like to hear other people's thoughts on it as well.

[hr]

My thoughts are purely based on describing your code intent. 0 implies working with numbers, whereas NULL implies working with pointers; even though pointers are a number, their usage and purpose is different enough that instantly discerning what is what makes code (very slightly) easier to read.

Example:
this->object = 0;
Is 'object' an integer index into an array where the object is found, or is it a pointer to the object itself? Granted, better naming also helps alleviate this confusion, but there is no denying that strict usage of NULL and 0 would help where improper naming causes confusion.

Looking for an alternative perspective, Bjarne Stroustrup says this:
In C++, the definition of NULL is 0, so there is only an aesthetic difference. I prefer to avoid macros, so I use 0. Another problem with NULL is that people sometimes mistakenly believe that it is different from 0 and/or not an integer. In pre-standard code, NULL was/is sometimes defined to something unsuitable and therefore had/has to be avoided. That's less common these days.
If you have to name the null pointer, call it nullptr; that's what it's called in C++11. Then, "nullptr" will be a keyword.[/quote]

So his complaints are:

  • Macros are evil
  • People are ignorant
  • Older compilers are broken

All valid-ish points. Here are suggested fixes:

Macros are evil
The problems usually associated with macro mis-use doesn't apply to a single '0'. 0 cannot be accidentally be used in any way that I can think of, which might mess up operator precedence or anything like that.

But if you are absolutely intent on avoiding macros, use a constant:
const size_t MyNull = 0;

People are ignorant
Perhaps, but the key then is to educate them. Either that, or don't let them near your code, since there are more dangerous issues in C++ that ignorance of NULL.

Older compilers are broken
So use a modern compiler? Older compilers mess up in other ways as well. Shall we not use the parts of the standard that older compilers got wrong?

However, he does make a good point about "If you have to name the null pointer, call it nullptr; that's what it's called in C++11."
If, for some reason, you are set against using NULL as a macro, and decided to use a constant, you might as well use this as your constant:
#if __cplusplus < 201103L
const size_t nullptr = 0;
#endif

It'll only be defined (I think) if C++11's nullptr is not available.

[hr]

When you add C++11's nullptr into the mix, nullptr is obviously the superior choice because not only does it declare your intent, but it also provides additional type-safe protections. But between the outdated NULL and 0, what are your thoughts on the matter?
Advertisement
Defining nullptr as size_t is not a good idea (will it work at all for assignments to pointer?)
Better use this: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/nullptr#Solution_and_Sample_Code

const // It is a const object...
class nullptr_t
{
public:
template<class T>
inline operator T*() const // convertible to any type of null non-member pointer...
{ return 0; }

template<class C, class T>
inline operator T C::*() const // or any type of null member pointer...
{ return 0; }

private:
void operator&() const; // Can't take address of nullptr

} nullptr = {};
NULL specifies intent.

There are also a few edge cases (especially on embedded hardware) where 0 != (void*)0 and the automatic conversion doesn't quite work right.
I'm using [font=courier new,courier,monospace]0[/font] even though my compiler supports [font=courier new,courier,monospace]nullptr[/font], and every single time I have a bad conscience (knowing that [font=courier new,courier,monospace]nullptr [/font]is the correct-correct thing to use). However, [font=courier new,courier,monospace]0[/font] is quick to type, and it's an idiom I've gotten used to during the years. The C++ standard makes the conversion from a zero literal to the null pointer of a type well defined too, so meh... one cannot even argue that it's wrong to use [font=courier new,courier,monospace]0[/font]. Actually, it's quite correct.

[font=courier new,courier,monospace]NULL [/font]on the other hand has two properties that turn me off. It's a macro, and it's an all-caps name. I really, really, really hate reading all-caps text.
Zero (0). Because what would Stroustrup do?
0 because I never know what header has the definition for NULL. I know it's a lame argument, but it's true. Then I read that Stroustrup prefers 0 also, so 0 it is.

Also, it doesn't really matter much for how I write code these days. For the most part I only use null pointers to pass them to functions like time(), or some Unix system calls.

Older compilers are broken
So use a modern compiler? Older compilers mess up in other ways as well. Shall we not use the parts of the standard that older compilers got wrong?

This strikes me as an unreasonable argument. If you were in a situation where "use a modern compiler" was an option, then you wouldn't be in a situation where you would need to choose between NULL and 0 in the first place.

Personally, I use 0 as I've run into too many C programmers who couldn't be bothered to include a compiler header that defines NULL and would stick #define NULL ((void*)0) in their own code.
0. Or nullptr in modern C++.

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

[font=times new roman,times,serif]NULL all the way. My thoughts:[/font]

[font=times new roman,times,serif]NULL does imply intent in a way that is far superior to 0. It is clean, concise, and like its C roots, is consistent with macro naming conventions. It is much easier to accidentally create ambiguity with 0 as in the OP's example. While I agree that "nullptr" might also adequately solve the semantic problem, it is redundant to NULL's precedent, longer to type, and doesn't stand out as much. Also, it is not supported everywhere yet--and while I appreciate that that means you should get a better compiler, why do we even need a new keyword when we already have one?[/font]

[font=times new roman,times,serif]As a macro, it can easily be changed for platform-specific purposes, and does not incur the overhead of a full variable, even with a crappy compiler. I suppose pathologically contrived macro redefinitions could cause a problem, but this could be solved in C++ by making NULL a keyword instead of a macro--not making a completely new keyword that does exactly the same thing.[/font]

[font=times new roman,times,serif]Further, macros are not inherently evil. When used incompetently, sure, they can cause many many problems. But macros were invented to make coding easier and more understandable. Whether using macros to write most of your code is good practice is a different argument, but in the case of NULL it's basically what macros were invented for--"to abstract away magic numbers without additional runtime overhead".[/font]

[font=times new roman,times,serif]C and C++ are different languages, but there's no fundamental reason why they should be more different than they need to be. Regularly, I write small modules in C, refactoring into C++ when a more elaborate design becomes necessary. NULL and nullptr serve the same purpose, so why can't we use the one that everyone already uses? Using nullptr implies that tons of perfectly good, readable code would need to get rewritten to handle the new standard--unless of course NULL and nullptr end up coexisting side-by-side, which would be worse.[/font]

[size="1"]And a Unix user said rm -rf *.* and all was null and void...|There's no place like 127.0.0.1|The Application "Programmer" has unexpectedly quit. An error of type A.M. has occurred.
[size="2"]

0 because easier to write.
No need read too much in to this simple issue.

nullptr in c++11 is nice tho.

This topic is closed to new replies.

Advertisement