16

I am currently in the process of reading a book on C++, and in this book the author explains that it is better to use a constant rather than NULL macro, but without really explaining why or giving any advantages or disadvantages.

So why it's better to do use:

const int NULL = 0;
int *ptr = NULL;

instead of:

int *ptr = NULL;

The only explanation is given is that the NULL macro is not type-safe.

jotik
  • 17,044
  • 13
  • 58
  • 123
simon
  • 1,180
  • 3
  • 12
  • 33
  • 30
    Use nullptr , according to Mordern c++ – Ajay May 17 '16 at 07:13
  • 7
    [The `NULL` macro](http://en.cppreference.com/w/cpp/types/NULL) must first of all be a macro. Second of all it must either be constant rvalue evaluated as zero, be an actual zero or other platform-specific value that when converted to a pointer is a null pointer, or be a `nullptr_t` prvalue (like `nullptr`). The macro is typically defined as `0` or `nullptr` (depending on C++ specification used by the compiler). Using a variable makes no sense, and vill also cause conversion problems. – Some programmer dude May 17 '16 at 07:18
  • 2
    Also it's important to note that [`NULL` in C++](http://en.cppreference.com/w/cpp/types/NULL) is different from [`NULL` in C](http://en.cppreference.com/w/c/types/NULL) (in C `NULL` is generally defined as `((void *) 0)`). – Some programmer dude May 17 '16 at 07:25
  • 5
    Books which tell you what to do without saying why are rather useless. – Daniel Daranas May 17 '16 at 07:25
  • 13
    And the book really tells you to define an integer constant named NULL? If that is true, don't use it any longer. –  May 17 '16 at 07:44
  • Yes the book tells to use `const int NULL`, but but the book dates 2014... @mani66 – simon May 17 '16 at 07:47
  • 6
    @simon that never was and never will be a good advise. –  May 17 '16 at 07:53
  • The book is wrong. The 0 must be a *literal*, not a const variable. Also the standard includes will step on that definition. And 0 is the same type as the const so huh? – JDługosz May 17 '16 at 08:44
  • 2
    "but without really explaining why" -> seriously, I want to know what *on earth* the author's reasoning for this nonsense actually was. – Alex Celeste May 17 '16 at 11:37
  • @simon pray tell, what's the title & the author of the said book? –  May 17 '16 at 14:53
  • It's French c++ book "Programmer en langage C++" by Claude Delannoy @vaxquis – simon May 17 '16 at 15:11
  • 2
    @simon which edition of the book, and on which chapter/page does the author state that it's better to use const instead of NULL macro, precisely? –  May 17 '16 at 15:21
  • 1
    What compiler even compiles that code? If NULL is a macro, it will be replaced before compilation and the result is something like `const int 0 = 0;` or `const int __null = 0;` which is invalid. I just tried with gcc and get `error: expected unqualified-id before ‘__null’` – Josef May 18 '16 at 06:52

4 Answers4

40

All are out of date.

Use nullptr instead. That's a special value for a pointer that doesn't point to anything. It even has its own type, std::nullptr_t.

There's no guarantee that the address 0x0 corresponds to the "uninitialised" pointer value, but note that the literal 0 is guaranteed to convert to the null pointer value.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 20
    Er... what? A literal `0` is still guaranteed to convert implicitly to a null pointer. –  May 17 '16 at 07:14
  • 6
    But there is a guarantee that `ptr=0;` will assign the pointer `ptr` the platform appropriate null value. – Chris Becke May 17 '16 at 07:14
  • 4
    @hvd only if it's a compile-time constant expression of integral type (which a `const int` global object is not, not even if it was initialized with the literal `0`.) – The Paramagnetic Croissant May 17 '16 at 07:14
  • 4
    @TheParamagneticCroissant Wrong on both counts. A `const int` global object *is* a compile-time constant expression in contexts where the initialiser is visible, and can be used in contexts where a constant expression suffices (e.g. template arguments), but despite that, isn't a null pointer constant, because the rule is no longer that it has to be a compile-time constant expression of integral type with a value of zero, but a literal `0`. –  May 17 '16 at 07:52
  • 1
    I like how this not only doesn't answer the question but also promotes confusion. – uh oh somebody needs a pupper May 17 '16 at 11:04
  • 2
    @hvd *A literal `0` is still guaranteed to convert implicitly to a null pointer.* I'd say it's *explicit*, given **4.10 Pointer Conversions**: "A *null pointer constant* is an integral constant expression prvalue of integer type that evaluates to zero or a prvalue of type `std::nullptr_t`." – Andrew Henle May 17 '16 at 12:20
  • 2
    @AndrewHenle Heh, yeah, the standard is explicit about it. That's not what I meant. I was talking about implicit vs. explicit conversions. :) –  May 17 '16 at 12:31
  • 1
    @hvd I assume Bathsheba mixed up two things: `0` (which is *always* converted to a specific, valid null pointer, *usually* pointer to 0x0 on desktop machines) and pointer to 0x0 (which *usually* is a null pointer, but strictly doesn't have to be one, as null pointer can have any value a compiler/platform desires; on some platforms (uC come to mind), 0x0 is actually a quite valid memory address). –  May 17 '16 at 15:26
  • 1
    I've put in the correct language for my boss. Ain't I nice? – P45 Imminent May 17 '16 at 16:05
  • Terribly nice. But it's even better now slodge. – Bathsheba May 17 '16 at 16:07
  • @hvd standard quote or it didn't happen – The Paramagnetic Croissant May 17 '16 at 17:22
  • @TheParamagneticCroissant I'm sure you're already very familiar with the rule that says `const`-qualified `int` objects can be used as constant expressions, since that was in since C++98. As for the other one, about only literal zero being a valid null pointer constant, not other constant expressions, this was [CWG issue 903](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#903), where you can see not only what changed to make it so, but also the discussion leading to that decision. –  May 17 '16 at 17:30
22

If you are using C++11 then its advisable to use nullptr instead of NULL.

Below are a few lines from The C++ Programming Language by Bjarne Stroustrup

  • In older code, 0 or NULL is typically used instead of nullptr (§7.2.2). However, using nullptr eliminates potential confusion between integers (such as 0 or NULL) and pointers (such as nullptr).
  • there are differences in the definition of NULL in different implementations; for example, NULL might be 0 or 0L. In C, NULL is typically (void∗)0, which makes it illegal in C++ (§7.2.1):
  • Using nullptr makes code more readable than alternatives and avoids potential confusion when a function is overloaded to accept either a pointer or an integer

I hope this will help you to understand.

Manthan Tilva
  • 3,135
  • 2
  • 17
  • 41
1

The author is right that preprocessor macros are not typed (in contrary to e.g. variables, where typing is enforced during their declaration). So macros are more dangerous in this regard, as compiler is unable to verify type correctness in expressions and you may miss an important warning/error message during compilation

Of course compiler creators can (and usually do, I hope) provide a version of NULL macro that expands to a value with a cast, equivalent (not identical!) to the C definition:

#define N ((void*)0)

BTW: since C++11 NULL can evaluate to std::nullptr_t type.

So I would not expect too much problems with NULL, but you may consider avoiding using your own macros. Or at least use your macros with caution as long as you are not perfectly sure that you can foresee the many contexts in which your macro may happen to be expanded in various expressions.

For a short exercise, you can try the below, to see that macros have no type, so their type gets deduced in the expressions, subject to e.g. arithmetic conversions or promotions. In the below example, MY_NULL macros (=without casting) result in quite dangerous assignments. That is what your book author has in mind and tries to warn you.

MY_TYPED macros evaluate to casted expressions, which ensures that compilers catches error when trying e.g. i = MY_TYPED_NULL;

#define MY_NULL 0
#define MY_TYPED_NULL ((void*)0)
int i;
float f;
void* v;
i = MY_NULL;    // bad: no compiler error
f = MY_NULL;    // bad: no compiler error
v = MY_NULL;    // seems to match programmer's intention
i = MY_TYPED_NULL;    // good: compiler error
f = MY_TYPED_NULL;    // good: compiler error
v = MY_TYPED_NULL;    // correct
Artur Opalinski
  • 1,052
  • 7
  • 12
  • 1
    I don't know, why people keep saying that. Of course things like `NULL` have a type (it is an abomination for other reasons). It's only macro parameters, that might be problematic. – MikeMB May 17 '16 at 07:28
  • 1
    NULL in C++ is and allways was simply 0, because thats the way it works in C++. –  May 17 '16 at 07:49
  • @manni66:you are right, but you only speak of **value**. My point is about **type** – Artur Opalinski May 17 '16 at 07:58
  • @MikeMB: tried to address your concern in the `exercise` added to my answer – Artur Opalinski May 17 '16 at 07:59
  • @Artur Opalinski the type of the evalueted NULL macro is integer, not any pointer type. Thats the reason why it was abused to even initialize integers to 0, so no one can define NULL to nullptr today. –  May 17 '16 at 08:22
  • @manni66: Sorry to oppose you again: macros do not have types. The type of the value that the macro expands to can be (should be, even!) buried in the definition of the macro if programmer does not intend to rely on luck. Pre C++11 compilers had no standard-compliant way to cast NULL (but still they could be non-standard compliant in this regard). It changed with C++11 standard providing nullptr_t. So now finally there is a type to cast NULL to - and a NULL definition should contain such cast, for the reasons explained in my answer. – Artur Opalinski May 17 '16 at 08:46
  • 1
    So? I'm not sure, what your exercise is supposed to prove. The problem isn't that NULL (or rather the expression it evaluates to) doesn't have a type, but that the Standard allows an implicit conversion from the integer literal `0` (which has a type) to a pointer type. I'm not saying that using macros when there is a better alternative is a good idea or anything. Just that your example doesn't show that NULL doesn't have a type. But I think I've misinterpreted the meaning of your initial statement. – MikeMB May 17 '16 at 09:34
  • 1
    To cite the standard (N3242) "The macro NULL is an implementation-defined C++ null pointer constant in this International Standard (4.10)." and "Possible definitions include 0 and 0L, but not (void*)0." –  May 17 '16 at 11:30
  • @manni66 You're certainly right that `(void*)0` is nowhere near a legal C++ definition of `NULL` (it couldn't be assigned to pointers-to-member, for example). At the same time, `nullptr` is a 100% legal option for the definition of `NULL`. It would break a lot of legacy code, but if a compiler was willing to live with that, it would have every right to do so. – Angew is no longer proud of SO May 17 '16 at 12:09
1

Indeed, the "NULL macro" is not type-safe. That means your compiler doesn't know if you're using the right type. For example, when using memcpy:

SomeClass a;
AnotherClass b;
memcpy((void*)&a, (void*)&b, sizeof(b));

(taken from there)

The compiler only sees two pointers in memory. But SomeClass and AnotherClass are incomplete types.

As others said, if you can use C++11, just use nullptr.

Community
  • 1
  • 1
Rosh Donniet
  • 418
  • 2
  • 10
  • 3
    This has nothing to do with `NULL`, but with the type-unsafe `void*` generic pointer type. Also, using `memcpy` in C++ is generally not a good idea. – Some programmer dude May 17 '16 at 07:22