Jump to content

  • Log In with Google      Sign In   
  • Create Account

NULL vs 0


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
45 replies to this topic

Poll: NULL vs 0 (81 member(s) have cast votes)

When nullptr isn't available, which do you prefer? Why?

  1. NULL (48 votes [59.26%] - View)

    Percentage of vote: 59.26%

  2. 0 (29 votes [35.80%] - View)

    Percentage of vote: 35.80%

  3. Custom type (4 votes [4.94%] - View)

    Percentage of vote: 4.94%

Vote Guests cannot vote

#21 Toothpix   Crossbones+   -  Reputation: 810

Like
0Likes
Like

Posted 14 December 2012 - 08:03 PM

I would say it depends, but for things that remain mostly static, I use 0, BUT keep everything to do with it well commented.

C dominates the world of linear procedural computing, which won't advance. The future lies in MASSIVE parallelism.


Sponsor:

#22 Cornstalks   Crossbones+   -  Reputation: 6985

Like
0Likes
Like

Posted 14 December 2012 - 08:06 PM

But if you are absolutely intent on avoiding macros, use a constant:

const size_t MyNull = 0;


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?)
[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#23 Ryan_001   Prime Members   -  Reputation: 1390

Like
0Likes
Like

Posted 14 December 2012 - 10:59 PM

I personally preferred 0 till nullptr came around. There was no overwhelming reason, it just seemed to read better IMO.

#24 Hodgman   Moderators   -  Reputation: 30349

Like
2Likes
Like

Posted 14 December 2012 - 11:39 PM

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 myVar = 0 means "set myVar to a null pointer value" or "set myVar to the integer value of zero", 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?
unsigned long long mask = 1<<48;
assert( mask == 0x1000000000000 );

0 because I never know what header has the definition for NULL.

I'm in the same boat.
I like the fact that nullptr is now a part of the language, so it works everywhere... but NULL has the problem that it's not part of the language; if you don't include some specific header (possibly one of many headers that conditionally define it), then this "keyword" doesn't exist.
I don't like having to include unnecessary headers, so I instead evaluate the macro in my head and write 0.

#25 L. Spiro   Crossbones+   -  Reputation: 13573

Like
1Likes
Like

Posted 15 December 2012 - 12:21 AM

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?

unsigned long long mask = 1<<48;
assert( mask == 0x1000000000000 );

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, 15 December 2012 - 04:53 AM.

It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#26 kunos   Crossbones+   -  Reputation: 2207

Like
0Likes
Like

Posted 15 December 2012 - 12:32 AM

I used to use NULL, now it's nullptr.
Stefano Casillo
Lead Programmer
TWITTER: @KunosStefano
AssettoCorsa - netKar PRO - Kunos Simulazioni

#27 Cornstalks   Crossbones+   -  Reputation: 6985

Like
1Likes
Like

Posted 15 December 2012 - 12:56 AM

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?

unsigned long long mask = 1<<48;
assert( mask == 0x1000000000000 );


I'll bite. The first line is undefined behavior on your average system where int is 32 bits, seeing as 1 << 48 is interpreted and evaluated as an int, and shifting by more than 31 bits is undefined behavior on a 32-bit data type. The type of 0x1000000000000 will be long long (again, assuming your average system), but the comparison will be meaningless because of the previous undefined behavior (and as L. Spiro points out, mask will likely be zero).

And for the thread: I always used NULL because I found it to be a bit more self documenting than 0, but I also hated the fact that it was a macro and not built into the language's syntax. So I guess my official answer is: I always used NULL, but I also always hated it.
[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#28 nife87   Members   -  Reputation: 516

Like
0Likes
Like

Posted 15 December 2012 - 03:37 AM

Although NULL IS ugly, it cannot be replaced with 0 (like others have explained). But you can always "rename" stuff in C/C++, so while it has been long since I last came across a compiler without support for nullptr, I would just redefine NULL as nullptr since I would probably also build the source on C++0x/C++11 complaint compilers, Of course, you loose the type of nullptr when compiling for pre-C++0x (std::nullptr_t) but with a little care (only load/store and compare with pointers), I cannot see why it would cause trouble.
#ifdef THIS_COMPILERS_VERSION_IS_WAY_TOO_OLD_FOR_MY_TASTE
#define nullptr NULL
#endif

EDIT: An enhanced version might look like this, since it does not pollute the global namespace and even gives nullptr a type:
namespace SuperLibrary
{
#ifdef THIS_COMPILERS_VERSION_IS_WAY_TOO_OLD_FOR_MY_TASTE
const void *nullptr = (unsigned)NULL;
#endif
...
}

Edited by nife87, 15 December 2012 - 03:39 AM.


#29 Hodgman   Moderators   -  Reputation: 30349

Like
1Likes
Like

Posted 15 December 2012 - 05:24 AM

Although NULL IS ugly, it cannot be replaced with 0

What? NULL is #defined as 0, meaning there's absolutely no difference except style/personal preference, and Bjarne "C++" Stroustrup was quoted earlier as preferring 0 (or nullptr in C++11 where available) over the NULL macro.

Edited by Hodgman, 15 December 2012 - 05:27 AM.


#30 SiCrane   Moderators   -  Reputation: 9593

Like
1Likes
Like

Posted 15 December 2012 - 05:26 AM

#2: 0 is the only literal constant that is defined by the standard to be implicitly castable to a pointer of any kind,

No, any integer constant expression that evaluates to zero is a valid null pointer constant. This includes 0 but also includes (1-1), (0xful >> 10), and '\0'. The standard specifically lists both 0 and 0L as two legal options for NULL. The latter is used by some compilers where an int is not the same size as a pointer, but a long is. This can give narrowing conversion warnings when trying to assign a NULL to a regular int. See the previously mentioned sections 8.1 in C++98/C++03 and 8.2 in C++11, as well as sections 4.10 and 5.19 (same number for all three).

I would just redefine NULL as nullptr since I would probably also build the source on C++0x/C++11 complaint compilers, Of course, you loose the type of nullptr when compiling for pre-C++0x (std::nullptr_t) but with a little care (only load/store and compare with pointers), I cannot see why it would cause trouble.

Again, as previously mentioned, NULL has an integer type which does not play happily with things like function overloads and template type deduction. If you have an overloaded function void foo(int) and void foo(void *), foo(NULL) calls the first overload but foo(nullptr) calls the second overload. Similarly if you have a vector<int *>, std::fill(vec.begin(), vec.end(), NULL) will fail to compile but std::fill(vec.begin(), vec.end(), nullptr) should.

const void *nullptr = (unsigned)NULL;

This is not a valid replacement for the C++11 nullptr. First, as previously mentioned, a void pointer cannot be assigned to other pointer types without an explicit cast. Basic usage such as int * a = nullptr; would fail. Second, this isn't a constant expression. You've defined nullptr as a non-const pointer to const void. Presumably you wanted some variation with const on the right hand side of the * to make the pointer itself const. But also, even when dealing with void pointers you can still get into a situation where you need a cast because a const void * is not assignable to a volatile void * without a cast.

Edited by SiCrane, 15 December 2012 - 05:28 AM.


#31 Yrjö P.   Crossbones+   -  Reputation: 1412

Like
0Likes
Like

Posted 15 December 2012 - 05:51 AM

Stroustrup in the C++ FAQ:
"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."

I think that makes sense. Use nullptr, and if you need pre-C++11 compatibility, define nullptr yourself conditionally like Servant of the Lord suggests, except make the definition as standard-conforming as possible (as shown by Martins Mozeiko) instead of just 0. If you needed both C++ and C compatibility, you'd have to likewise conditionally define nullptr as (void*)0 for C.

NULL is fine in pure C code, but there doesn't seem to be any reason to use it in C++.

Edited by Stroppy Katamari, 15 December 2012 - 05:51 AM.


#32 nife87   Members   -  Reputation: 516

Like
1Likes
Like

Posted 15 December 2012 - 06:17 AM

Although NULL IS ugly, it cannot be replaced with 0

What? NULL is #defined as 0, meaning there's absolutely no difference except style/personal preference, and Bjarne "C++" Stroustrup was quoted earlier as preferring 0 (or nullptr in C++11 where available) over the NULL macro.


Sorry. I was under the impression that NULL was commonly defined 0, but was not required to be defined as such. Well, that certainly makes life a bit easier.

#33 SiCrane   Moderators   -  Reputation: 9593

Like
1Likes
Like

Posted 15 December 2012 - 06:24 AM

No, you were right. NULL is not required to be 0. In C++, NULL can be defined to be any integral constant expression that evaluates to zero. As I already mentioned, the C++ standard lists two possible conforming definitons: 0 and 0L, though those aren't the only possibilities.

#34 Álvaro   Crossbones+   -  Reputation: 13291

Like
0Likes
Like

Posted 15 December 2012 - 06:24 AM

NULL is self documenting, but the documentation is misleading. It gives the impression that the compiler will know you are talking about a pointer, but that's not the case. As others have mentioned, if you have functions foo(int) and foo(int *), foo(NULL) will call the former. This is confusing as hell because NULL indicates one intent and the compiler does something else. IF you use 0, everyone knows what will happen. That seems more clear to me.

#35 mhagain   Crossbones+   -  Reputation: 7956

Like
0Likes
Like

Posted 15 December 2012 - 07:10 AM

NULL because reading code is harder than writing code, and using NULL makes it explicit that the variable being assigned to is a pointer type.

NULL is self documenting, but the documentation is misleading. It gives the impression that the compiler will know you are talking about a pointer, but that's not the case. As others have mentioned, if you have functions foo(int) and foo(int *), foo(NULL) will call the former. This is confusing as hell because NULL indicates one intent and the compiler does something else. IF you use 0, everyone knows what will happen. That seems more clear to me.


That doesn't actually resolve the initial problem you set out - even if you use 0 the wrong overload may still be called (assuming that foo (int *) was the intent). I'd go so far as to argue that using 0 instead of NULL is even more ambiguous in this case - when reading code, if you see a call to "foo (0)" how on earth are you going to know which overload the programmer intended? Using "foo (NULL)" at least gives you a chance - you know the programmer's intent straight away - they want the pointer version (the compiler may still get it wrong but at least you can now detect that and take appropriate remedial action).

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#36 bluepig.man   Members   -  Reputation: 412

Like
0Likes
Like

Posted 15 December 2012 - 07:19 AM

zero
it's convenient.(Maybe because lazy)
And it's direct,Others see it will soon know,there is nothing.

#37 Álvaro   Crossbones+   -  Reputation: 13291

Like
0Likes
Like

Posted 15 December 2012 - 08:15 AM

NULL because reading code is harder than writing code, and using NULL makes it explicit that the variable being assigned to is a pointer type.


NULL is self documenting, but the documentation is misleading. It gives the impression that the compiler will know you are talking about a pointer, but that's not the case. As others have mentioned, if you have functions foo(int) and foo(int *), foo(NULL) will call the former. This is confusing as hell because NULL indicates one intent and the compiler does something else. IF you use 0, everyone knows what will happen. That seems more clear to me.


That doesn't actually resolve the initial problem you set out - even if you use 0 the wrong overload may still be called (assuming that foo (int *) was the intent). I'd go so far as to argue that using 0 instead of NULL is even more ambiguous in this case - when reading code, if you see a call to "foo (0)" how on earth are you going to know which overload the programmer intended? Using "foo (NULL)" at least gives you a chance - you know the programmer's intent straight away - they want the pointer version (the compiler may still get it wrong but at least you can now detect that and take appropriate remedial action).


That argument is really strange. Nobody expects the foo(0) will call the pointer version. 0 is an int. If the intent is to call the pointer version, you should write a cast, or it won't work, whether you use NULL or 0. Once you use the cast, the intent is clear.

foo(0); // I want to call foo(int)
foo((int *)0); // I want to call foo(int*)
How is that not clear?

#38 Álvaro   Crossbones+   -  Reputation: 13291

Like
0Likes
Like

Posted 15 December 2012 - 08:30 AM

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?

unsigned long long mask = 1<<48;
assert( mask == 0x1000000000000 );


The literal "1" has type int. Probably "1ul" (if the compiler has 64-bit longs) or "1ull" was intended. [EDIT: Actually, the way the code is written, "1ull" was intended for sure.]

I am very careful to always use literals with the type I intend, since I was bitten by this one:
double limit_price = order.is_market() ? 0 : order.limit_price();
At the time when I wrote this code Order::limit_price() used to return a double, and all was good. Then someone changed that to return a type Price, which provided an implicit conversion to double. The person doing that is a C++ expert, he tested the code, and it worked fine. Then we changed compilers from gcc-2.95.2 to gcc-3.4 (yeah, this is years ago), and then prices started to get truncated to integer values. This was not caught when testing the new compiler version (because someone messed up), and we ended up sending incorrect reports to a market regulator for several days. I spent about two weeks cleaning up the mess.

It turns out the C++ standard specifies that truncating to int is the correct behavior. Recent versions of g++ will warn about this, but it took them a long time to do so.

Since then, I write 0.0 if I intend it to be a double, 0.0f if I intend it to be a float, etc. I also don't like implicit conversions and I would much rather have an explicit Price::as_double() method that I need to call explicitly.

Edited by Álvaro, 15 December 2012 - 08:33 AM.


#39 wack   Members   -  Reputation: 1303

Like
0Likes
Like

Posted 15 December 2012 - 09:08 AM

I spend a lot of time reading code, probably more than most. One of the few things that causes my brain to short-circuit for a while when doing this, is usage of 0 instead of NULL. For this reason, I have used NULL. Thankfully, so have most of the people whose code I have to read.

This is probably just learned preference, but thankfully we now do have somthing better, something that I have yearned for for a long time - a type safe null pointer!

Thanks Bjarne & co.

#40 L. Spiro   Crossbones+   -  Reputation: 13573

Like
0Likes
Like

Posted 15 December 2012 - 09:37 AM

0 is an int. If the intent is to call the pointer version, you should write a cast, or it won't work, whether you use NULL or 0. Once you use the cast, the intent is clear.

foo(0); // I want to call foo(int)
foo((int *)0); // I want to call foo(int*)
How is that not clear?

Because 0 as a literal constant (or anything that results in a 0 constant) can be implicitly cast to any built-in type.
So 0 is not necessarily an int.

The problem with writing a cast explicitly every time you want to make your intent clear is that it leaves you with a whole lot of typing and thought. You have to cast to the correct type every time whereas just using NULL retains the same intent while keeping the coding process to a minimum.


L. Spiro
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS