3

Why is there a NULL in the C language? Is there a context in which just plain literal 0 would not work exactly the same?

graywolf
  • 7,092
  • 7
  • 53
  • 77
  • 1
    Seeing as `NULL` is allowed to be defined as `0`, then necessarily every instance where `NULL` appears must, assuming ISO C, work the same if `0` were there. Mainly, it's syntactic sugar. – Nate Eldredge May 10 '20 at 21:13
  • Possible duplicate of https://stackoverflow.com/q/1296843/1126841. – chepner May 10 '20 at 21:13
  • But NULL may be defined like `((void*)0)` in C (not in C++). – numzero May 10 '20 at 21:15
  • 2
    @KenWhite the question is about C, not C++ – bruno May 10 '20 at 21:16
  • it is more readable to use NULL about a pointer rather than to use 0. When you see `if (a == NULL)` that help you to know `a` is (very probably) a pointer. but when you see `if (a == 0)` you first think about a number (even it can be a pointer too). – bruno May 10 '20 at 21:18
  • I've sometimes wondered if `NULL` was invented historically to try to support implementations where the null pointer wasn't represented by all-bits-zero, so that `NULL` could be defined instead to `0xffffffff` or whatever. Then there wouldn't be a need for the current rule that `0` must evaluate to a null pointer even if it's not all-bits-zero. But perhaps programmers couldn't get out of the habit of just using `0`, since the null pointer was all-bits-zero on their favorite platform, and the language had to adopt the current rule or else break all that code. – Nate Eldredge May 10 '20 at 22:26
  • @EricPostpischil: Sorry, which of my comments are you referring to? "Every `NULL` may be replaced with 0" is exactly what I said in my first comment. I never said that every `0` may be replaced by `NULL`. – Nate Eldredge May 11 '20 at 00:56
  • @EricPostpischil: My second comment was speculating that there may have once been an intention to migrate to a version of the language where `0` would *not* be allowed as a null pointer constant, and `NULL` would be required instead, and it would be allowed to expand to something other than `0` or `(void *)0`. Of course no such thing ever came to pass. – Nate Eldredge May 11 '20 at 00:57
  • @NateEldredge: Sorry, never mind. – Eric Postpischil May 11 '20 at 01:06

5 Answers5

5

Actually, you can use a literal 0 anyplace you would use NULL.

Section 6.3.2.3p3 of the C standard states:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

And section 7.19p3 states:

The macros are:

NULL

which expands to an implementation-defined null pointer constant

So 0 qualifies as a null pointer constant, as does (void *)0 and NULL. The use of NULL is preferred however as it makes it more evident to the reader that a null pointer is being used and not the integer value 0.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    The use of `NULL` is not just “preferred,” and this does not really answer the question the OP asked, “Is there a context in which just plain literal `0` would not work exactly the same?” That context is where an error such as where `x` is an `int *` and the programmer accidentally typed `*x = 0;` instead of `x = 0;`. In this case, the compiler cannot diagnose the error, but it could if `NULL` were used (and defined as `((void *) 0)`). So the difference is not just a matter if preference but has actual functional consequences. – Eric Postpischil May 10 '20 at 22:50
4

NULL is used to make it clear it is a pointer type.

Ideally, the C implementation would define NULL as ((void *) 0) or something equivalent, and programmers would always use NULL when they want a null pointer constant.

If this is done, then, when a programmer has, for example, an int *x and accidentally writes *x = NULL;, then the compiler can recognize that a mistake has been made, because the left side of = has type int, and the right side has type void *, and this is not a proper combination for assignment.

In contrast, if the programmer accidentally writes *x = 0; instead of x = 0;, then the compiler cannot recognize this mistake, because the left side has type int, and the right side has type int, and that is a valid combination.

Thus, when NULL is defined well and is used, mistakes are detected earlier.

In particular answer to your question “Is there a context in which just plain literal 0 would not work exactly the same?”:

  • In correct code, NULL and 0 may be used interchangeably as null pointer constants.
  • 0 will function as an integer (non-pointer) constant, but NULL might not, depending on how the C implementation defines it.
  • For the purpose of detecting errors, NULL and 0 do not work exactly the same; using NULL with a good definition serves to help detect some mistakes that using 0 does not.

The C standard allows 0 to be used for null pointer constants for historic reasons. However, this is not beneficial except for allowing previously written code to compile in compilers using current C standards. New code should avoid using 0 as a null pointer constant.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
2

It is for humans not compilers.

if I see in the code p = NULL; instead of p = 0; it is much easier for me to understand that p is a pointer not the integer.

For compilers it does not matter, for humans does.

Same as we use definitions instead of "raw" values or expressions or human readable variable names like loopCounter instead of p755_x.

0___________
  • 60,014
  • 4
  • 34
  • 74
  • No, `NULL` is beneficial for compilers as well. If, for some `int *x`, a programmer means to write `x = null pointer;` but types `*x = null pointer;`, the compiler authors would like to give the programmer an error or warning message. If the “null pointer” is `0`, the compiler cannot know a mistake has been made. If it is `NULL‘ (and the implementation defines it suitably, such as `((void *) 0)`, the compiler can recognize an error has been made. – Eric Postpischil May 10 '20 at 22:44
  • @EricPostpischil warning is for humans anyway :). Compiler does not care and it does not affect the code generation. https://godbolt.org/z/7hnxd3 . So I it is important for humans - not compilers – 0___________ May 10 '20 at 23:45
2

Why is there a NULL in the C language?

To help make clear the assignment implies a pointer and not an integer.

Example: strtok(char *s1, const char *s2); in both cases below receive a null pointer as the NULL and 0 are both converted to a char *. The first is usually considered better self-documentation. As a style issue, follow your group's coding standard.

strtok(s, NULL);
strtok(s, 0;

Is there a context in which just plain literal 0 would not work exactly the same?

Yes - when the original type is important.

0 is an int
NULL is a void *, or int, unsigned or long or long long, etc. It is implementation defined.

Consider a function that takes a variable number of pointers, with a sentinel null pointer to indicate the last.

foo("Hello", "World", NULL);  // might work if `NULL` is a pointer.
foo("Hello", "World", 0);

As the arguments as 0 and NULL are not converted when passed to a ... function (aside from some promotions), the function foo() might not access them the same. Portable code would use:

foo("Hello", "World", (char*) NULL);
// or 
foo("Hello", "World", (char*) 0);

A difference may also occur when NULL, 0 are passed to _Generic

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

The integer constant literal 0 has different meanings depending upon the context in which it's used. In all cases, it is still an integer constant with the value 0, it is just described in different ways. Namely, the most common purposes of NULL pointer are:

  1. To initialize a pointer variable when that pointer variable isn’t assigned any valid memory address yet.
  2. To check for a null pointer before accessing any pointer variable. By doing so, we can perform error handling in pointer related code e.g. dereference pointer variable only if it’s not NULL.
  3. To pass a null pointer to a function argument when we don’t want to pass any valid memory address.(ref)
miador
  • 358
  • 1
  • 5
  • 20