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.
Null macro is defined in stdio. h and stddef.h.It is used to represent a null pointer in your code. its value is zero. Null pointer is same as an uninitialized pointer..
Traditionally, the NULL macro is an implementation defined constant representing a null pointer, usually the integer 0 . In C, the NULL macro can have type void * .
The C NUL is a single character that compares equal to 0. The C NULL is a special reserved pointer value that does not point to any valid data object. The SQL null value is a special value that is distinct from all non-null values and denotes the absence of a (non-null) value.
It is often abbreviated as NUL (or NULL, though in some contexts that term is used for the null pointer). In 8-bit codes, it is known as a null byte. The original meaning of this character was like NOP—when sent to a printer or a terminal, it has no effect (some terminals, however, incorrectly display it as space).
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.
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.
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
.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With