Can '\ 0' and NULL be used interchangeably?

NULL is often used in the context of pointers and is defined using macros in several standard libraries (for example, <iostream> ) as an integer 0 . '\0' is a null character and is 8 bits of zeros. By the way, 8 bits of zeros is equivalent to the integer 0 .

In some cases, although it is believed to be a terrible style, these two can be used interchangeably:

 int *p='\0'; if (p==NULL) //evaluates to true cout << "equal\n"; 

or

 char a=NULL; char b='\0'; if (a==b) //evaluates to true cout << "equal again\n"; 

There are already many similar questions on SO only; for example, the top answer to this question ( What is the difference between NULL, '\ 0' and 0 ) says: "Actually, this is not the same."

Can someone provide an example that NULL and \0 cannot be interchangeable (preferably the actual application, not the pathological case)?

+54
c ++ null
Nov 03 '16 at 6:23
source share
7 answers

Can someone provide an example that NULL and \ 0 cannot be replaced?

The difference between NULL and '\0' may affect overload resolution.

Example ( check it out on Coliru ):

 #include <iostream> // The overloaded function under question can be a constructor or // an overloaded operator, which would make this example less silly void foo(char) { std::cout << "foo(char)" << std::endl; } void foo(int) { std::cout << "foo(int)" << std::endl; } void foo(long) { std::cout << "foo(long)" << std::endl; } void foo(void*) { std::cout << "foo(void*)" << std::endl; } int main() { foo('\0'); // this will definitely call foo(char) foo(NULL); // this, most probably, will not call foo(char) } 

Note that the gcc compiler used in Coliru defines NULL as 0L , which for this example means that foo(NULL) allowed by foo(long) , not foo(void*) . Ville-Valtteri Tiittanen's answer discusses this aspect in detail.

+51
Nov 03 '16 at 7:01
source share

Defining a NULL Macro in C ++

Leon is right. that if there are several overloads for the same function, \0 prefer the one that takes a parameter of type char . However, it is important to note that in a typical NULL compiler, it will prefer overloading, which takes an argument of type int rather than type void* !

What probably causes this confusion is that the C language allows you to define NULL as (void*)0 . The C ++ standard explicitly states (draft N3936, p. 444) :

Possible definitions [from the NULL macro] include 0 and 0L , but not (void*)0 .

This restriction is necessary because, for example, char *p = (void*)0 is a valid C, but invalid C ++, whereas char *p = 0 is valid in both cases.

In C ++ 11 and later, you should use nullptr if you need a null constant that behaves like a pointer.

How Leon’s proposal works in practice

This code defines several overloads of one function. Each overload displays a parameter type:

 #include <iostream> void f(int) { std::cout << "int" << std::endl; } void f(long) { std::cout << "long" << std::endl; } void f(char) { std::cout << "char" << std::endl; } void f(void*) { std::cout << "void*" << std::endl; } int main() { f(0); f(NULL); f('\0'); f(nullptr); } 

In Ideone, this outputs

 int int char void* 

Therefore, I would say that the problem with overloads is not an actual application, but a pathological case. The NULL constant will behave incorrectly and should be replaced with nullptr in C ++ 11.

What if null is not zero?

Another pathological case was proposed by Andrew Keaton on another issue:

Note that this is a null pointer in C. It does not matter for the underlying architecture. If the underlying architecture has a null pointer value defined as the address 0xDEADBEEF, then the compiler should sort this mess.

Thus, even in this ridiculous architecture, there are still ways to check for a null pointer:

 if (!pointer) if (pointer == NULL) if (pointer == 0) 

The following are WRONG ways to check for a null pointer:

 #define MYNULL (void *) 0xDEADBEEF if (pointer == MYNULL) if (pointer == 0xDEADBEEF) 

since they are considered by the compiler as normal comparisons.

Summary

In general, I would say that the differences are mostly stylistic. If you have a function that accepts int and overloads that accepts char , and they work differently, you will notice the difference when you call them with constants \0 and NULL . But as soon as you put these constants in variables, the difference disappears, because the called function is subtracted from the type of the variable.

Using the right constants makes the code more maintainable and conveys the value better. You should use 0 when you mean a number, \0 when you mean a character, and nullptr when you mean a pointer. Matthieu M. points out in the comments that GCC had an error in which a char* compared with \0 , while the goal was to dereference the pointer and compare a char with \0 . Such errors are easier to detect if the correct style is used thoroughly for the code base.

To answer your question, there really is no actual use case that would prevent you from using \0 and NULL interchangeably. Just stylistic reasons and some extreme cases.

+36
Nov 03 '16 at 8:31
source share

Please, do not do that. This is an anti-pattern, and in fact it is wrong. NULL for NULL pointers, '\0' is the null character. They are logically different things.

I don't think I've ever seen this:

 int* pVal='\0'; 

But this is pretty common:

 char a=NULL; 

But this is not a good form. This makes the code less portable and, in my opinion, less readable. This will probably also cause problems in mixed C / C ++ environments.

It relies on assumptions about how any particular implementation defines NULL. For example, some implementations use simple

 #define NULL 0 

Others may use:

 #define NULL ((void*) 0) 

And I saw how others were defined as an integer, and all kinds of odd treatment.

NULL should, in my opinion, be used solely to indicate an invalid address. If you need a null character, use '\0' . Or define it as NULLCHR . But it is not so clean.

This will make your code more portable - you won’t start getting warnings about types, etc. if you change the compiler / environment / compiler settings. This may be more important in C or a mixed C / C ++ environment.

Example warnings that may occur: Consider this code:

 #define NULL 0 char str[8]; str[0]=NULL; 

This is equivalent to:

 #define NULL 0 char str[8]; str[0]=0; 

And we assign an integer char value. This can cause a compiler warning, and if that is enough, pretty soon you will not see any important warnings. And for me this is a real problem. The presence of warnings in the code has two side effects:

  • Given enough warnings, you do not see new ones.
  • It gives a signal that the warnings are acceptable.

In both cases, actual errors can slip that would be caught by the compiler if we bother to read the warnings (or turn on -Werror)

+8
Nov 03 '16 at 6:41
source share

Yes, they can exhibit different behaviors when performing overloaded functions.

func('\0') calls func(char) ,

while

func(NULL) calls func(integer_type) .




You can eliminate the confusion by using nullptr , which is always a pointer type, does not display ambiguity when assigning / comparing a value or overloading a function's resolution.

 char a = nullptr; //error : cannot convert 'std::nullptr_t' to 'char' in initialization int x = nullptr; //error : nullptr is a pointer not an integer 

Note that it is still NULL compatible:

 int *p=nullptr; if (p==NULL) //evaluates to true 

Excerpt from C ++ Programming Book of the 4th edition of Straustrup:

In older code, 0 or NULL is usually used instead of 0ptpt (Β§7.2.2). However, using nullptr eliminates the potential confusion between integers (e.g. 0 or NULL) and pointers (such as nullptr).




+8
Nov 03 '16 at 6:53
source share

Computer programs have two types of readers.

The first type is computer programs, such as a compiler.

The second type is people like you and your colleagues.

Programs are generally fine with getting one type of zero instead of another. There are exceptions, as other answers pointed out, but this is not very important.

The important thing is that you mess with human readers.

Human readers are very sensitive to context. Using zero zero, you're lying for you readers. They will curse you.

A trusted person can more easily miss mistakes.
A person who is lied to can see "mistakes" that are not there. When "correcting" these phantom errors, they introduce real errors.

Do not lie to your people. One of the people you lie to is your future. You will curse you too.

+6
Nov 04 '16 at 8:08
source share

Excerpts from the C ++ 14 N3936 project:

18.2 Types [support.types]

3 The NULL macro is the C ++ null pointer pointer constant specified in this International Standard (4.10).

4.10 Pointer conversions [conv.ptr]

1 The null pointer constant is an integer literal (2.14.2) with a value of 0 or a value of type std::nullptr_t .
The null pointer constant can be converted to a pointer type; the result is a null pointer value of this type and is different from any other object pointer value or function pointer type.

Thus, NULL can be any integer literal with a value of 0 or a value of type std::nullptr_t , like nullptr , while '\0' always the null character of a narrow character.

Thus, not generally interchangeable, although in the pointer context you do not see any stylistic difference.

Example:

 #include <iostream> #include <typeinfo> int main() { std::cout << typeid('\0').name << '\n' << typeid(NULL).name << '\n' << typeid(nullptr).name << '\n'; } 
+4
Nov 03 '16 at 7:33
source share

Define that is NULL in C / C ++.

According to C / C ++, a NULL reference is defined as a macro that expands to a null pointer constant. Further we can read that the null pointer constant can be converted to any type of pointer (or member-type-pointer) that receives the value of the null pointer. This is a special value indicating that the pointer does not point to any object.

Definition related to C:

The null pointer constant is an integral constant expression that evaluates to zero (for example, 0 or 0L) or cast such a value for type void * (for example (void *) 0).

Definition related to C ++ 98:

The null pointer constant is an integral constant expression that evaluates to zero (for example, 0 or 0L).

Definition related to C ++ 11:

A null pointer constant is either an integral constant expression that evaluates to zero (for example, 0 or 0L), or a value of type nullptr_t (for example, nullptr).

An example of overload methods.

Suppose we have the following methods:

 class Test { public: method1(char arg0); method1(int arg0); method1(void* arg0); method1(bool arg0); } 

A call to method1 with an argument NULL or nullptr should call method1(void* arg0); . However, if we call method1 with the argument '\0' or 0 , we should execute method1(char arg0); and method1(int arg0); .

+1
Nov 05 '16 at 10:19
source share



All Articles