74

I was interviewing a guy for a mid-level software engineering position yesterday, and he mentioned that in C, NULL is not always zero and that he had seen implementations of C where NULL is not zero. I find this highly suspect, but I want to be sure. Anyone know if he is right?

(Responses will not affect my judgement on this candidate, I've already submitted my decision to my manager.)

chi42
  • 925
  • 1
  • 7
  • 8
  • http://bytes.com/topic/c/answers/213647-null-c – soandos Mar 27 '12 at 16:50
  • related http://stackoverflow.com/questions/459743/is-null-always-false – mcabral Mar 27 '12 at 16:52
  • 2
    http://c-faq.com/null/index.html – Jouni K. Seppänen Mar 27 '12 at 16:53
  • 2
    No, but zero is always `NULL`. – Philip Mar 27 '12 at 17:08
  • @Philip: Only the literal zero, not necessarily other zeroes. – Dietrich Epp Nov 06 '12 at 14:23
  • @DietrichEpp: what other zeros are there? – Philip Nov 06 '12 at 14:41
  • 6
    @Philip: `int x = 0; void *p = (void *) x;` Here, `x` has the value zero, but `x` is not the literal zero, so `p` is not guaranteed to be `NULL`, and on some bizarre platforms it actually won't be `NULL`. On the other hand, `void *q = 0;` always assigns `NULL` to `q`, no matter what platform. "Literal" in this context has a technical meaning. Search for "integer literal". – Dietrich Epp Nov 06 '12 at 23:08
  • For a more complete answer than those posted below, check out [What's the difference between null pointers and NULL?](https://software.codidact.com/posts/278657) To actually answer the question, an answer must separate the terms null pointers, null pointer constants and the NULL macro. – Lundin Oct 04 '21 at 13:16

5 Answers5

75

I'm assuming you mean the null pointer. It is guaranteed to compare equal to 0.1 But it doesn't have to be represented with all-zero bits.2

See also the comp.lang.c FAQ on null pointers.


  1. See C99, 6.3.2.3.
  2. There's no explicit claim; but see the footnote for C99, 7.20.3 (thanks to @birryree in the comments).
Cristian Ciupitu
  • 20,270
  • 7
  • 50
  • 76
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 8
    As an addendum to your C99 reference, as `NULL` always compares equal to `0` (null pointer constant), section 7.20.3.2 also notes that all bits set to zero (such as the case for `calloc`) is not necessarily the same as the representation of `0.0f` or integer `0`. – wkl Mar 27 '12 at 16:57
  • Awesome. So it's pretty common practice these days, but not a requirement. Thanks. – chi42 Mar 27 '12 at 16:59
  • 1
    So if I were to cast a NULL pointer to an int, and then print it, I would not print '0'? Does that mean the compiler has to remember when it's doing a pointer comparison so that it can make a NULL pointer compare equal to zero? – chi42 Mar 27 '12 at 17:02
  • 6
    @chi42: The standard doesn't say anything about what happens when you convert a pointer (any pointer) to an int, other than that it's implementation-defined. See 6.3.2.3 again. – Oliver Charlesworth Mar 27 '12 at 17:04
  • How can NULL be equal to 0, whose bit representation is all zeros (right?), but still be equal to 0? – einpoklum Jun 30 '21 at 20:24
17

§ 6.3.2.3 of the C99 standard says

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.

§ 7.17 also says

[...] NULL which expands to an implementation-defined null pointer constant [...]

The address of the NULL pointer might be different from 0, while it will behave like it was in most cases.

(This should be the same as in older C standards, which I don't have at hand right now)

johannes
  • 15,807
  • 3
  • 44
  • 57
15

The null pointer constant is always 0. The NULL macro may be defined by the implementation as a naked 0, or a cast expression like (void *) 0, or some other zero-valued integer expression (hence the "implementation defined" language in the standard).

The null pointer value may be something other than 0. When a null pointer constant is encountered, it will be converted to the proper null pointer value.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • 3
    Color me stupid, but I'm afraid I need more education now. When you have a pointer `ptr`, isn't `ptr==NULL` _exactly_ the same as `ptr==0` or `!ptr`? Is this implementation dependent? – Mr Lister Mar 27 '12 at 19:21
  • 5
    @MrLister: In the context of your *source code*, you're absolutely correct - `ptr == 0` and `ptr == NULL` and `!ptr` are all equivalent. Once the source code has been translated to machine code, however, the actual null pointer value may be something other than 0 (and all of those comparisons will be against that actual null pointer value). – John Bode Mar 27 '12 at 23:48
  • 1
    `The null pointer value may be something other than 0` - do you mean `*ptr == something` even if `void *ptr = 0`? – Incerteza Sep 07 '14 at 09:58
  • 6
    @AlexanderSupertramp: I mean that the *runtime environment* in which a program executes may use a value other than 0 to represent a "null" pointer (that is, a well-defined *invalid* address value). On some systems, `0` may be a perfectly valid memory address accessible by your program, and a different value (such as, say, `0xFFFFFFFF`) may be used for "null" . However, within your *source code*, a 0-valued expression is always used to represent the `NULL` pointer constant. – John Bode Feb 27 '15 at 17:58
  • Just a noob question: Just wanted to know whether I'm correct when I say "the value of a `null` pointer is equal to the value contained in a memory location where this memory location is arbitrarily chosen(just guessing) or chosen by the compiler at run-time and when we write `char *p = NULL;` then p points to this memory location.". Kindly correct me. – asn Aug 02 '19 at 08:46
  • Also, the question is suppose the location `0xFFFFFFFF` is chosen as `NULL`. Then, Is there any way that the compiler uses to protect the value in this location from being changed? Also, in the case where `0xFFFFFFFF` is chosen as `NULL`, then would writing `char *f = (char*)0xFFFFFFFF;` make f point to `NULL`? How do we know what numerical value in a program apart from 0 is being treated as `NULL`? Also, In the case, where any other value apart from 0 is being treated as `NULL`. Does `char *p = (char*)0` still be treated as `NULL`? – asn Aug 02 '19 at 09:25
  • @Jos - As far as your *source code* is concerned, `NULL` is **always** zero valued. All I was trying to point out is that `NULL` doesn’t necessarily mean address 0 in *physical* memory, but that detail is hidden behind the `NULL` abstraction. And what may be the null pointer value is physical memory may not be the same as what’s used in virtual memory. – John Bode Aug 02 '19 at 11:00
11

In C, there is one, and only one, context where it is necessary to explicitly cast a null pointer constant to a specific pointer type in order for the program to operate correctly. That context is passing a null pointer through an untyped function argument list. In modern C, this only happens when you need to pass a null pointer to a function that takes a variable number of arguments. (In legacy C, it happens with any function not declared with a prototype.) The paradigmatic example is execl, where the very last argument must be a null pointer explicitly cast to (char *):

execl("/bin/ls", "ls", "-l", (char *)0);    // correct
execl("/bin/ls", "ls", "-l", (char *)NULL); // correct, but unnecessarily verbose

execl("/bin/ls", "ls", "-l", 0);            // undefined behavior
execl("/bin/ls", "ls", "-l", NULL);         // ALSO undefined behavior

Yes, that last example has undefined behavior even if NULL is defined as ((void *)0), because void * and char * are not implicitly interconvertible when passed through an untyped argument list, even though they are everywhere else. (There is language in C2011 that makes them implicitly interconvertible when passed through va_arg, but they forgot to specify that implementation-provided library functions access variadic arguments as-if by calling va_arg, so you can only rely on that for variadic functions that are part of your program. Someone should probably file a DR.)

"Under the hood", the problem here is not just with the bit pattern used for a null pointer, but that the compiler may need to know the exact concrete type of each argument in order to set up a call frame correctly. (Consider the MC68000, with its separate address and data registers; some ABIs specified pointer arguments to be passed in address registers but integer arguments in data registers. Consider also any ABI where int and void * are not the same size. And it's vanishingly rare nowadays, but C does still explicitly provide for void * and char * not being the same size. [EDIT: I'm not sure, but this may no longer be permitted.]) If there's a function prototype, the compiler can use that, but unprototyped functions and variadic arguments offer no such assistance.

C++ is more complicated and I don't feel qualified to explain how.

zwol
  • 135,547
  • 38
  • 252
  • 361
2

On some implementations, size of pointer is not the same as the size of integer. NULL in integer context is 0, but the actual binary layout does not have to be all 0s.

Craig McQueen
  • 41,871
  • 30
  • 130
  • 181
pizza
  • 7,296
  • 1
  • 25
  • 22