Sign in to follow this  
Servant of the Lord

NULL vs 0


Recommended Posts

[[size=2]forked from [url="http://www.gamedev.net/topic/635759-problems-with-my-custom-linked-list-class/page__p__5010690#entry5010690"]Problems with my custom linked list class[/url][/size]]

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

Another forummer responded,
[quote]...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 ([i]very [/i]slightly) easier to read.

Example:
[code]this->object = 0;[/code]
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, [url="http://www.stroustrup.com/bs_faq2.html#null"]Bjarne Stroustrup[/url] says this:
[quote]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:[list]
[*]Macros are evil
[*]People are ignorant
[*]Older compilers are broken
[/list]
All valid-[i]ish[/i] points. Here are suggested fixes:

[b]Macros are evil[/b]
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:
[code]const size_t MyNull = 0;[/code]

[b]People are ignorant[/b]
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.

[b]Older compilers are broken[/b]
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 "[i]If you have to name the null pointer, call it nullptr; that's what it's called in C++11.[/i]"
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:
[code]#if __cplusplus < 201103L
const size_t nullptr = 0;
#endif
[/code]
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?

Share this post


Link to post
Share on other sites
frob    44908
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
alvaro    21246
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.

Share this post


Link to post
Share on other sites
SiCrane    11839
[quote name='Servant of the Lord' timestamp='1355513391' post='5010709']
[b]Older compilers are broken[/b]
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?
[/quote]
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 [tt]#define NULL ((void*)0)[/tt] in their own code.

Share this post


Link to post
Share on other sites
Geometrian    1810
[font=times new roman,times,serif]NULL all the way. My thoughts:[/font]

[font=times new roman,times,serif]NULL [i]does[/i] 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--[i]not[/i] making a completely [i]new[/i] 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 [i]invented[/i] 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 [i]for[/i]--"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 [i]worse[/i].[/font]

Share this post


Link to post
Share on other sites
bubu LV    1436
SiCrane - I don't think it's true.
GCC (also Visual Studio) defines NULL like this: "#define NULL ((void *)0)" in stddef.h.
So:
[code]c:\ test>type a.cpp

#define NULL ((void*)0)
void foo(int);
void foo(void*);
int main()
{
foo(NULL);
}

c:\ test>g++ a.cpp
C:\Users\XXX\AppData\Local\Temp\ccAUKoxR.o:a.cpp:(.text+0x16): undefined reference to `foo(void*)'
collect2.exe: error: ld returned 1 exit status[/code]

foo(NULL) correctly calls foo(void*). Edited by Martins Mozeiko

Share this post


Link to post
Share on other sites
Flimflam    665
You know, I've always wondered, when they created the C++11 spec, why did they create "nullptr" instead of just using the reserved but functionless "null" keyword that already exists?

Was it because people were creating their own functionality for it via macros or what have you?

Share this post


Link to post
Share on other sites
alvaro    21246
[quote name='Flimflam' timestamp='1355524803' post='5010765']
You know, I've always wondered, when they created the C++11 spec, why did they create "nullptr" instead of just using the reserved but functionless "null" keyword that already exists?

Was it because people were creating their own functionality for it via macros or what have you?
[/quote]

"null" is a keyword in C++? I didn't know that... Or are you thinking of a different language?

Share this post


Link to post
Share on other sites
SiCrane    11839
[quote name='Martins Mozeiko' timestamp='1355524493' post='5010762']
SiCrane - I don't think it's true.
GCC (also Visual Studio) defines NULL like this: "#define NULL ((void *)0)" in stddef.h.
[/quote]
((void *)0) is not a legal definition for NULL in C++. It is a valid definition for NULL in C. So MSVC's NULL definition looks like:
[code]
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
[/code]
If you try using the ((void *)0) definition in C++ you get errors doing simple things like [tt]int * p = NULL;[/tt] since a void * can't be assigned to a non void pointer without a cast in C++. See sections 18.1 in the C++98 and C++03 and 18.2 in the C++11 standards where the footnotes specifically say that (void *)0 is not a legal definition for NULL.

Share this post


Link to post
Share on other sites
Flimflam    665
[quote name='Álvaro' timestamp='1355525475' post='5010768']
[quote name='Flimflam' timestamp='1355524803' post='5010765']
You know, I've always wondered, when they created the C++11 spec, why did they create "nullptr" instead of just using the reserved but functionless "null" keyword that already exists?

Was it because people were creating their own functionality for it via macros or what have you?
[/quote]

"null" is a keyword in C++? I didn't know that... Or are you thinking of a different language?
[/quote]
No, not officially. My wording was a bit misleading. In fact thinking back, I'm just confusing the functionality of an old compiler that had reserved it. I'm unaware if any others have since.

Share this post


Link to post
Share on other sites
bubu LV    1436
[quote name='SiCrane' timestamp='1355525563' post='5010770']
((void *)0) is not a legal definition for NULL in C++. It is a valid definition for NULL in C. So MSVC's NULL definition looks like:[/quote]
Yes, you're right. Sorry, I misread that #ifdef...

Share this post


Link to post
Share on other sites
Khatharr    8812
I actually was unpleasantly surprised recently when I was writing templates with no header inclusions and I discovered that NULL is not a keyword. (I always thought it was part of the language for some reason.)

In such files I took to saying:
[source lang="cpp"]#ifndef NULL
#define NULL 0
#endif[/source]

But I'm not using C++11 at the moment, so I don't have nullptr. There's some interesting things to consider in this thread, though. Thanks for starting this, SotL.

Share this post


Link to post
Share on other sites
wqking    761
Always NULL.
There are plenty of reasons, I listed some reasons in my early blog.
http://cpgf.org/blog/why-i-prefer-null-over-0-as-null-pointer.html

My primary three points,
1, Reason 1, NULL is self explained.
2, Reason 2, C++ standard saying NULL is 0 doesn't mean null pointer is 0
3, Reason 3, C++11 supports nullptr, everyone will prefer nullptr to 0, then why don't we use NULL than 0 in pre-C++11 era?

And I have tough time to conver C++ code with 0 as pointer to Lua code, but maybe only I do it :)

However, nothing is correct or wrong, it is very subjective opinion, IMHO.

Share this post


Link to post
Share on other sites
MrJoshL    810
I would say it depends, but for things that remain mostly static, I use 0, [b][i][u]BUT[/u][/i][/b] keep everything to do with it well commented.

Share this post


Link to post
Share on other sites
Cornstalks    7030
[quote name='Servant of the Lord' timestamp='1355513391' post='5010709']
But if you are absolutely intent on avoiding macros, use a constant:
[code]const size_t MyNull = 0;[/code]
[/quote]

Ew, please no. I'd rather have someone just use 0 instead of a global variable like that, because at least 0 conveys more information than MyNull does (for example, can I trust that if I set a pointer to MyNull, that if (ptr) will be false?)

Share this post


Link to post
Share on other sites
Hodgman    51231
0 obviously gives the correct result, because NULL is defined as 0. The reason people use NULL over 0 is because it's self documenting -- a in-source comment saying this is a "zero pointer", whereas the literal "0" means many things depending on context. Generally, I like self-documenting code like this...

However, IMHO, there's usually enough context around to know whether [font=courier new,courier,monospace]myVar = 0[/font] means "[i]set [font=courier new,courier,monospace]myVar[/font] to a null pointer value[/i]" or "[i]set [font=courier new,courier,monospace]myVar[/font] to the integer value of zero[/i]", so I don't really see the need for the macro.

The same problem comes up in other situations BTW. As well as the type of literal "0" being ambiguous, there's many similar situations that a C++ programmer should be aware of. e.g. what's the type of the literal "1" below, and does the assertion fail?
[code]unsigned long long mask = 1<<48;
assert( mask == 0x1000000000000 );[/code]
[quote name='Álvaro' timestamp='1355518336' post='5010730']0 because I never know what header has the definition for NULL.[/quote]I'm in the same boat.
I like the fact that [font=courier new,courier,monospace]nullptr[/font] is now a part of the language, so it works everywhere... but [font=courier new,courier,monospace]NULL[/font] has the problem that it's not part of the language; if you don't include some specific header ([i]possibly one of many headers that conditionally define it[/i]), then this "[i]keyword[/i]" doesn't exist.
I don't like having to include unnecessary headers, so I instead evaluate the macro in my head and write [font=courier new,courier,monospace]0[/font].

Share this post


Link to post
Share on other sites
L. Spiro    25621
[quote name='Hodgman' timestamp='1355549999' post='5010854']
The same problem comes up in other situations BTW. As well as the type of literal "0" being ambiguous, there's many similar situations that a C++ programmer should be aware of. e.g. what's the type of the literal "1" below, and does the assertion fail?
[code]unsigned long long mask = 1<<48;
assert( mask == 0x1000000000000 );[/code]
[/quote]
The assert() will be triggered since mask will be 0.

I prefer self-documenting code and always use NULL. It is theoretical that NULL could be defined as something other than 0 but:
#1: It wouldn’t change the integrity of my code as long as I am always using NULL to check for invalid pointers as apposed to mixing between if ( ptr == NULL ) and if ( !ptr ).
#2: 0 is the only literal constant that is defined by the standard to be implicitly castable to a pointer of any kind, thus the idea that NULL could be something other than 0 is only theoretical, and anyone who ends up in such a situation brought it upon him- or her- self.


L. Spiro Edited by L. Spiro

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this