Can I use NULL as substitution for the value of 0?

C++CPointersNullLanguage Lawyer

C++ Problem Overview


Am I allowed to use the NULL pointer as replacement for the value of 0?

Or is there anything wrong about that doing?


Like, for example:

int i = NULL;

as replacement for:

int i = 0;

As experiment I compiled the following code:

#include <stdio.h>

int main(void)
{
    int i = NULL;
    printf("%d",i);

    return 0;
}

Output:

0

Indeed it gives me this warning, which is completely correct on its own:

warning: initialization makes integer from pointer without a cast [-Wint-conversion] 

but the result is still equivalent.


  • Am I crossing into "Undefined Behavior" with this?
  • Is it permissible to utilize NULL in this way?
  • Is there anything wrong with using NULL as a numerical value in arithmetical expressions?
  • And what is the result and behavior in C++ for this case?

I have read the answers of https://stackoverflow.com/questions/1296843/what-is-the-difference-between-null-0-and-0 about what the difference between NULL, \0 and 0 is, but I did not get the concise information from there, if it is quite permissible and also right to use NULL as value to operate with in assignments and other arithmetical operations.

C++ Solutions


Solution 1 - C++

> Am I allowed to use the NULL pointer as replacement for the value of 0?

No, it is not safe to do so. NULL is a null-pointer constant, which could have type int, but which more typically has type void * (in C), or otherwise is not directly assignable to an int (in C++ >= 11). Both languages allow pointers to be converted to integers, but they do not provide for such conversions to be performed implicitly (though some compilers provide that as an extension). Moreover, although it is common for converting a null pointer to an integer to yield the value 0, the standard does not guarantee that. If you want a constant with type int and value 0 then spell it 0.

> - Am I might crossing into Undefined Behavior with this?

Yes, on any implementation where NULL expands to a value with type void * or any other not directly assignable to int. The standard does not define the behavior of your assignment on such an implementation, ergo its behavior is undefined.

> - is it permissible to operate with the NULL in that way?

It is poor style, and it will break on some systems and under some circumstances. Inasmuch as you appear to be using GCC, it would break in your own example if you compiled with the -Werror option.

> - Is there anything wrong about to use NULL as numerical value in arithmetical expressions?

Yes. It is not guaranteed to have a numerical value at all. If you mean 0 then write 0, which is not only well defined, but shorter and clearer.

> - And how is the result in C++ to that case?

The C++ language is stricter about conversions than is C and has different rules for NULL, but there, too, implementations may provide extensions. Again, if you mean 0 then that's what you should write.

Solution 2 - C++

NULL is some null pointer constant. In C it could be an integer constant expression with value 0 or such an expression cast to void*, with the latter more likely. Which means you can't assume to use NULL interchangeably with zero. For instance, in this code sample

char const* foo = "bar"; 
foo + 0;

Replacing 0 with NULL is not guaranteed to be a valid C program, because addition between two pointers (let alone of different pointer types) is not defined. It will cause a diagnostic to be issued due to a constraint violation. The operands for addition will not be valid.


As for C++, things are somewhat different. Lack of an implicit conversion from void* to other object types meant that NULL was historically defined as 0 in C++ code. In C++03, you could probably get away with it. But since C++11 it can legally be defined as the nullptr keyword. Now again producing an error, since std::nullptr_t may not be added to pointer types.

If NULL is defined as nullptr then even your experiment becomes invalid. There is no conversion from std::nullptr_t to an integer. That is why it is considered a safer null pointer constant.

Solution 3 - C++

> Am I allowed to use the NULL pointer as a replacement for the value of 0? > > int i = NULL;

The rules vary between languages and their versions. In some cases you can and in others, you can't. Regardless, you shouldn't. If you're lucky, your compiler will warn when you attempt it or even better, fail to compile.

In C++, prior to C++11 (quote from C++03):

> [lib.support.types] > > NULL is an implementation-defined C++ null pointer constant in this International Standard.

It makes little sense to use a null pointer constant as an integer. However...

> [conv.ptr] > > A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero.

So, it would technically work even if it's nonsensical. Due to this technicality, you may encounter poorly written programs that abuse NULL.

Since C++11 (quote from latest draft):

> [conv.ptr] > > A null pointer constant is an integer literal ([lex.icon]) with value zero or a prvalue of type std​::​nullptr_­t.

A std​::​nullptr_­t is not convertible to an integer, so using NULL as integer would work only conditionally, depending on choices made by the language implementation.

P.S. nullptr is a prvalue of type std​::​nullptr_­t. Unless you need your program to compile in pre-C++11, you should always use nullptr instead of NULL.


C is a bit different (quotes from C11 draft N1548):

> 6.3.2.3 Language / Conversions / Other operands / Pointers > > 3 An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. ...

So, the case is similar to post C++11 i.e. the abuse of NULL works conditionally depending on choices made by the language implementation.

Solution 4 - C++

Yes, though depending on the implementation you may need a cast. But yes, it is 100% legitimate, otherwise.

Although it is really, really, really bad style (needless to say?).

NULL is, or was, actually not C++, it is C. The standard does however, like for many C legacies, have two clauses ([diff.null] and [support.types.nullptr]) which technically make NULL C++. It is an implementation-defined null-pointer constant. Therefore, even if it's bad style, it's technically as C++ as it can be.
As pointed out in the footnote, possible implementations could be 0 or 0L, but not (void*)0.

NULL could, of course (the standard doesn't explicitly say so, but it's pretty much the only choice remaining after 0 or 0L) be nullptr. That's almost never the case, but it is a legal possibility.

The warning that the compiler showed to you demonstrates that the compiler is in fact not compliant (unless you compiled in C mode). Because, well, according to the warning, it did convert a null pointer (not nullptr which would be of nullptr_t, which would be distinct), so apparently the definition of NULL is indeed (void*)0, which it may not be.

Either way, you have two possible legitimate (i.e. compiler not broken) cases. Either (the realistic case), NULL is something like 0 or 0L, then you have "zero or one" conversions to integer, and you are good to go.

Or NULL is indeed nullptr. In that case you have a distinct value that has guarantees about comparison as well as clearly-defined conversions from integers, but unluckily not to integers. It does, however, have a clearly-defined conversion to bool (resulting in false), and bool has a clearly-defined conversion to integer (resulting in 0).

Unluckily, that's two conversions, so it's not within "zero or one" as pointed out in [conv]. Thus, if your implementation defines NULL as nullptr, then you will have to add an explicit cast for your code to be correct.

Solution 5 - C++

From the C faq:

> Q: If NULL and 0 are equivalent as null pointer constants, which should I use? > > A: It is only in pointer contexts that NULL and 0 are equivalent. NULL should not be used when another kind of 0 is required, even though it might work, because doing so sends the wrong stylistic message. (Furthermore, ANSI allows the definition of NULL to be ((void *)0), which will not work at all in non-pointer contexts.) In particular, do not use NULL when the ASCII null character (NUL) is desired. Provide your own definition > > http://c-faq.com/null/nullor0.html

Solution 6 - C++

Disclaimer: I don't know C++. My answer is not meant to be applied in the context of C++

'\0' is an int with value zero, just 100% exactly like 0.

for (int k = 10; k > '\0'; k--) /* void */;
for (int k = 10; k > 0; k--) /* void */;

In the context of pointers, 0 and NULL are 100% equivalent:

if (ptr) /* ... */;
if (ptr != NULL) /* ... */;
if (ptr != '\0') /* ... */;
if (ptr != 0) /* ... */;

are all 100% equivalent.


Note about ptr + NULL

The context of ptr + NULL is not that of pointers. There is no definition for the addition of pointers in the C language; pointers and integers can be added (or subtracted). In ptr + NULL if either ptr or NULL is a pointer, the other must be an integer, so ptr + NULL is effectively (int)ptr + NULL or ptr + (int)NULL and depending on the definitions of ptr and NULL several behaviours can be expected: it all working, warning for conversion between pointer and integer, failure to compile, ...

Solution 7 - C++

No, not anymore preferred to use NULL(old way of pointer initilization).

Since C++11:

The keyword nullptr denotes the pointer literal. It is a prvalue of type std::nullptr_t. There exist implicit conversions from nullptr to null pointer value of any pointer type and any pointer to member type. Similar conversions exist for any null pointer constant, which includes values of type std::nullptr_t as well as the macro NULL.

https://en.cppreference.com/w/cpp/language/nullptr

Actually, std::nullptr_t is the type of the null pointer literal, nullptr. It is a distinct type that is not itself a pointer type or a pointer to member type.

#include <cstddef>
#include <iostream>
 
void f(int* pi)
{
   std::cout << "Pointer to integer overload\n";
}
 
void f(double* pd)
{
   std::cout << "Pointer to double overload\n";
}
 
void f(std::nullptr_t nullp)
{
   std::cout << "null pointer overload\n";
}
 
int main()
{
    int* pi; double* pd;
 
    f(pi);
    f(pd);
    f(nullptr);  // would be ambiguous without void f(nullptr_t)
    // f(0);  // ambiguous call: all three functions are candidates
    // f(NULL); // ambiguous if NULL is an integral null pointer constant 
                // (as is the case in most implementations)
}

Output:

Pointer to integer overload
Pointer to double overload
null pointer overload

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRobertS supports Monica CellioView Question on Stackoverflow
Solution 1 - C++John BollingerView Answer on Stackoverflow
Solution 2 - C++StoryTeller - Unslander MonicaView Answer on Stackoverflow
Solution 3 - C++eerorikaView Answer on Stackoverflow
Solution 4 - C++DamonView Answer on Stackoverflow
Solution 5 - C++phuclvView Answer on Stackoverflow
Solution 6 - C++pmgView Answer on Stackoverflow
Solution 7 - C++Build SucceededView Answer on Stackoverflow