42

I have seen below macro in many topmost header files:

#define NULL 0  // C++03

In all over the code, NULL and 0 are used interchangeably. If I change it to.

#define NULL nullptr  // C++11

Will it cause any bad side effect ? I can think of the only (good) side effect as following usage will become ill-formed;

int i = NULL;
iammilind
  • 62,239
  • 27
  • 150
  • 297

6 Answers6

40

I have seen below macro in topmost header file:

You shouldn't have seen that, the standard library defines it in <cstddef> (and <stddef.h>). And, IIRC, according to the standard, redefining names defined by standard header files results in undefined behaviour. So from a purely standardese viewpoint, you shouldn't do that.


I've seen people do the following, for whatever reason their broken mind thought of:

struct X{
  virtual void f() = NULL;
}

(As in [incorrectly]: "set the virtual table pointer to NULL")

This is only valid if NULL is defined as 0, because = 0 is the valid token for pure-virtual functions (§9.2 [class.mem]).

That said, if NULL was correctly used as a null pointer constant, then nothing should break.

However, beware that, even if seemingly used correctly, this will change:

void f(int){}
void f(char*){}

f(0); // calls f(int)
f(nullptr); // calls f(char*)

However, if that was ever the case, it was almost certainly broken anyways.

Xeo
  • 123,374
  • 44
  • 277
  • 381
  • `You shouldn't have seen that`. Why you feel so ? I have even seen a strange macro like, `#define NULL (void*)(0)` in a production code for DSP for WCDMA L1. – iammilind Jan 25 '12 at 13:30
  • 7
    Is `virtual void f() = 0L;` legal? Because `#define NULL 0L` certainly is a conforming implementation. – Steve Jessop Jan 25 '12 at 13:32
  • 6
    @iammilind: You shouldn't, because `NULL` is already defined by the standard. – Xeo Jan 25 '12 at 13:32
  • Defining `NULL` as `(void*)(0)` is C, defining it as `0` is C++. – spraff Jan 25 '12 at 13:32
  • @Steve: IIRC, it's not. The only valid "pure-virtual-specifier" token is `=0`, but I'll look that up. – Xeo Jan 25 '12 at 13:33
  • @spraff: And `nullptr` is C++. – Xeo Jan 25 '12 at 13:33
  • `nullptr` is C++11, the world is still using C++03 :-) – spraff Jan 25 '12 at 13:35
  • 1
    @iammilind: because it is UB to redefine standard macros. The implementation's own header files are permitted to contain code that relies on `NULL` expanding to whatever the implementation says it expands to. In the case of `NULL` it could make a difference if the implementation (unwisely IMO, but legally) passes `NULL` as varargs parameter in a context where the function expects a pointer, secure in the knowledge that *under its calling convention*, `NULL` is the right size and will work. If you've changed it from, say, `0L` to `0` before including that header then you could break it. – Steve Jessop Jan 25 '12 at 13:35
  • 8
    @Steve: `§9.2 [class.mem]`: `pure-specifier: = 0`. – Xeo Jan 25 '12 at 13:37
  • 1
    @SteveJessop, unfortunately potential UB are accepted GB (Good Behavior!) in some old implementations. I am not the one, who have done such `#define`s, but they are there as part of legacy. :) – iammilind Jan 25 '12 at 13:38
  • @iammilind: sure, but having seen code with UB that works on a particular implementation (or a particular program), it's probably not a good idea to use that as evidence that you should write code with similar but different UB. It may be that defining it `0` was OK, but defining it `nullptr` was not. You just don't know until you try, and maybe not even then. So Xeo is absolutely right to say that "from a standardese viewpoint, you shouldn't do that". – Steve Jessop Jan 25 '12 at 13:46
  • 12
    Btw, if you're writing a C++11 implementation then it is legal for you to `#define NULL nullptr`, because `nullptr` is a null pointer constant, and `NULL` can be any null pointer constant. But programs aren't allowed to decide for themselves which one it should be, that's up to the implementation. – Steve Jessop Jan 25 '12 at 13:51
  • 1
    Your virtual thing is only valid if the impl defines NULL as 0. Not every implementation necessarily does that. – Johannes Schaub - litb Jan 25 '12 at 17:54
  • @Johannes: That was my point. Maybe I should change the "because" to "if", though. – Xeo Jan 25 '12 at 18:55
15

Far better is to search and replace NULL with nullptr throughout the code.

It may be syntactically safe, but where would you put the #define? It creates code organisation problems.

spraff
  • 29,265
  • 19
  • 105
  • 197
  • 10
    `g++ -DNULL=nullptr ...` :) – Xeo Jan 25 '12 at 13:31
  • 7
    I consider code which requires certain compiler flags to be non-portable. – spraff Jan 25 '12 at 16:43
  • Well, I guess we can't -DWindows, or anything like that anymore, and we need to rewrite all our code ground up to port it to another platform... –  Jan 25 '12 at 18:31
  • 3
    Having an *optional* `-Dmode` switch is reasonable, assuming the code can still compile without it. Also, not every project needs to be cross-platform, but in that case, you shouldn't need to `-DWindows` or `-DAnythingElse` because it's built-in. – spraff Jan 26 '12 at 08:33
7

No. You're not allowed to (re)define standard macros. And if you see

#define NULL 0

at the top of any file other than a standard header (and even there, it should be in include guards, and typically in additional guards as well), then that file is broken. Remove it.

Note that good compilers will typically define NULL with something like:

#define NULL __builtin_null

, to access a compiler builtin which will trigger a warning if it is used in a non-pointer context.

James Kanze
  • 142,482
  • 15
  • 169
  • 310
4

You shouldn't be defining it at all, unless you're writing your own version of <cstddef>; it certainly shouldn't be in "many topmost header files".

If you are implementing your own standard library, then the only requirement is

18.2/3 The macro NULL is an implementation-defined C++ null pointer constant

so either 0 or nullptr is acceptable, and nullptr is better (if your compiler supports it) for the reason you give.

Mike Seymour
  • 235,407
  • 25
  • 414
  • 617
4

Maybe Not

If you have a particular format of overloading behaviour:

void foo(int);
void foo(char*);

Then the behaviour of the code:

foo(NULL);

will change depending on whether NULL is changed to nullptr or not.

Of course, there's another question as to whether it's safe to write such code as is present in this answer...

Kaz Dragon
  • 6,266
  • 2
  • 32
  • 44
2

While it might break backwards-compatibility with older stuff that was badly written (either that, or overly clever...), for your newer code, this is a non-issue. You should use nullptr, and not NULL, where you mean nullptr. Also, you should use 0 where you mean zero.

Anders Marzi Tornblad
  • 17,122
  • 9
  • 50
  • 62
  • 3
    Bear in mind that well-written older stuff won't use `nullptr` either, since it was only added to the language a few months ago. – Mike Seymour Jan 25 '12 at 13:39
  • 1
    @Mike: well-written older stuff might have something like `#define NULLPTR NULL`, though, which can be changed to `#define NULLPTR nullptr` when compiling as C++11. And then all instances of `NULLPTR` in the code removed once you're confident that you'll never again have to compile it as C++03. – Steve Jessop Jan 25 '12 at 13:57
  • 1
    @SteveJessop Seriously? I mean, maybe now that we know about nullptr that NULLPTR macro would make sense, but old code(*before* nullptr was added to the standard) having that seems.. unlikely. – luiscubal Jan 25 '12 at 14:54
  • @luiscabal: Bjarne Stroustrup has been advising people do so something along those lines for years. Although C++11 was only published in September, `nullptr` was in C++0x drafts for a long time before that. It wasn't a surprise! – Steve Jessop Jan 25 '12 at 15:24
  • 1
    Ah, I've just checked and I slightly misremembered. Stroustrup's C++ FAQ says to call it `nullptr`, not `NULLPTR`. Personally I wouldn't define a macro in C++03 for a symbol that I knew was due to become a keyword, that's why I said `NULLPTR` rather than `nullptr`. But it's perfectly valid provided you ensure that the macro isn't defined when building as C++11. – Steve Jessop Jan 25 '12 at 15:26
  • 2
    @SteveJessop "...I wouldn't define a macro in C++03 for a symbol that I knew was due to become a keyword..." Isn't that exactly the point of the including this particular preprocessor directive? If you are writing it for C++03 then you don't need to include anything at all. I go with #define nullptr NULL to compile on my non C++11 compiler in the knowledge that one day I should be able to scrap the macro altogether. In the mean time I have more readable code that is compatible with the latest standard. – Mike G May 07 '12 at 07:35