The C FAQ has some examples of historical machines with non-0 NULL representations.

From The C FAQ List, question 5.17:

Q: Seriously, have any actual machines really used nonzero null pointers, or different representations for pointers to different types?

A: The Prime 50 series used segment 07777, offset 0 for the null pointer, at least for PL/I. Later models used segment 0, offset 0 for null pointers in C, necessitating new instructions such as TCNP (Test C Null Pointer), evidently as a sop to [footnote] all the extant poorly-written C code which made incorrect assumptions. Older, word-addressed Prime machines were also notorious for requiring larger byte pointers (char *'s) than word pointers (int *'s).

The Eclipse MV series from Data General has three architecturally supported pointer formats (word, byte, and bit pointers), two of which are used by C compilers: byte pointers for char * and void *, and word pointers for everything else. For historical reasons during the evolution of the 32-bit MV line from the 16-bit Nova line, word pointers and byte pointers had the offset, indirection, and ring protection bits in different places in the word. Passing a mismatched pointer format to a function resulted in protection faults. Eventually, the MV C compiler added many compatibility options to try to deal with code that had pointer type mismatch errors.

Some Honeywell-Bull mainframes use the bit pattern 06000 for (internal) null pointers.

The CDC Cyber 180 Series has 48-bit pointers consisting of a ring, segment, and offset. Most users (in ring 11) have null pointers of 0xB00000000000. It was common on old CDC ones-complement machines to use an all-one-bits word as a special flag for all kinds of data, including invalid addresses.

The old HP 3000 series uses a different addressing scheme for byte addresses than for word addresses; like several of the machines above it therefore uses different representations for char * and void * pointers than for other pointers.

The Symbolics Lisp Machine, a tagged architecture, does not even have conventional numeric pointers; it uses the pair <NIL, 0> (basically a nonexistent <object, offset> handle) as a C null pointer.

Depending on the "memory model" in use, 8086-family processors (PC compatibles) may use 16-bit data pointers and 32-bit function pointers, or vice versa.

Some 64-bit Cray machines represent int * in the lower 48 bits of a word; char * additionally uses some of the upper 16 bits to indicate a byte address within a word.

Answer from janks on Stack Overflow
🌐
TutorialsPoint
tutorialspoint.com › c_standard_library › c_macro_null.htm
C library - NULL Macro
The C library NULL Macro represent the value of a null pointer constant that may be defined as ((void*)0), 0 or 0L depending on the compiler vendor. ... NULL (void*)0: A null pointer cast to the void* type.
🌐
Quora
quora.com › What-is-Null-Macro-in-C
What is Null Macro in C? - Quora
Answer (1 of 3): 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..It does not point anywhere.
Discussions

c - When was the NULL macro not 0? - Stack Overflow
Bring the best of human thought and AI automation together at your work. Explore Stack Internal ... I vaguely remember reading about this a couple of years ago, but I can't find any reference on the net. Can you give me an example where the NULL macro didn't expand to 0? More on stackoverflow.com
🌐 stackoverflow.com
c - Correct way of defining NULL and NULL_POINTER? - Stack Overflow
As far as I know, C defines NULL like this: #define NULL ( (void *) 0) Then, how should we define NULL_POINTER ? I defined it the same in my program and it worked, but I suppose that is just a More on stackoverflow.com
🌐 stackoverflow.com
struct - Passing NULL as argument to a C macro - Stack Overflow
So how would I achieve what I am trying to do. The arg1 might or might not be available when the macro is invoked. I need to send in a NULL value to satisfy the macro's definition. Sorry for the noob question. ... Why use a macro? Seems like a function might work fine here. ... C? More on stackoverflow.com
🌐 stackoverflow.com
linux - Meaning of NULL definition for a macro in C - Stack Overflow
I was writing a simple code for accessing my driver data through entry in the procfs. While going through the header file proc_fs.h, I came across a macro like: #define proc_create(name, mode, par... More on stackoverflow.com
🌐 stackoverflow.com
January 27, 2020
Top answer
1 of 7
42

The C FAQ has some examples of historical machines with non-0 NULL representations.

From The C FAQ List, question 5.17:

Q: Seriously, have any actual machines really used nonzero null pointers, or different representations for pointers to different types?

A: The Prime 50 series used segment 07777, offset 0 for the null pointer, at least for PL/I. Later models used segment 0, offset 0 for null pointers in C, necessitating new instructions such as TCNP (Test C Null Pointer), evidently as a sop to [footnote] all the extant poorly-written C code which made incorrect assumptions. Older, word-addressed Prime machines were also notorious for requiring larger byte pointers (char *'s) than word pointers (int *'s).

The Eclipse MV series from Data General has three architecturally supported pointer formats (word, byte, and bit pointers), two of which are used by C compilers: byte pointers for char * and void *, and word pointers for everything else. For historical reasons during the evolution of the 32-bit MV line from the 16-bit Nova line, word pointers and byte pointers had the offset, indirection, and ring protection bits in different places in the word. Passing a mismatched pointer format to a function resulted in protection faults. Eventually, the MV C compiler added many compatibility options to try to deal with code that had pointer type mismatch errors.

Some Honeywell-Bull mainframes use the bit pattern 06000 for (internal) null pointers.

The CDC Cyber 180 Series has 48-bit pointers consisting of a ring, segment, and offset. Most users (in ring 11) have null pointers of 0xB00000000000. It was common on old CDC ones-complement machines to use an all-one-bits word as a special flag for all kinds of data, including invalid addresses.

The old HP 3000 series uses a different addressing scheme for byte addresses than for word addresses; like several of the machines above it therefore uses different representations for char * and void * pointers than for other pointers.

The Symbolics Lisp Machine, a tagged architecture, does not even have conventional numeric pointers; it uses the pair <NIL, 0> (basically a nonexistent <object, offset> handle) as a C null pointer.

Depending on the "memory model" in use, 8086-family processors (PC compatibles) may use 16-bit data pointers and 32-bit function pointers, or vice versa.

Some 64-bit Cray machines represent int * in the lower 48 bits of a word; char * additionally uses some of the upper 16 bits to indicate a byte address within a word.

2 of 7
8

There was a time long ago when it was typed as ((void*)0) or some other machine-specific manner, where that machine didn't use the all-zero bit pattern.

Some platforms (certain CDC or Honeywell machines) had a different bit pattern for NULL (ie, not all zeros) although ISO/ANSI fixed that before C90 was ratified, by specifying that 0 was the correct NULL pointer in the source code, regardless of the underlying bit pattern. From C11 6.3.2.3 Pointers /4 (though, as mentioned, this wording goes all the way back to C90):

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.

🌐
C-faq
c-faq.com › null › macro.html
Question 5.4
A: As a matter of style, many programmers prefer not to have unadorned 0's scattered through their programs, some representing numbers and some representing pointers. Therefore, the preprocessor macro NULL is defined (by several headers, including <stdio.h> and <stddef.h>) as a null pointer constant, typically 0 or ((void *)0) (see also question 5.6).
🌐
Microsoft Learn
learn.microsoft.com › en-us › cpp › c-language › null-macro
NULL Macro | Microsoft Learn
Access to this page requires authorization. You can try changing directories. ... Several include files define the NULL macro as ((void *)0).
Find elsewhere
🌐
cppreference.com
en.cppreference.com › cpp › types › NULL
NULL - cppreference.com
January 3, 2025 - The macro NULL is an implementation-defined null pointer constant. ... In C, the macro NULL may have the type void*, but that is not allowed in C++ because null pointer constants cannot have that type.
🌐
O'Reilly
oreilly.com › library › view › c-in-a › 059600298X › re317.html
NULL macro - C++ In a Nutshell [Book]
May 8, 2003 - The NULL macro expands to a null pointer constant, such as 0 or 0L. Some C libraries declare NULL as ((void*)0) in stddef.h.
Author   Ray Lischner
Published   2003
Pages   808
🌐
Stack Overflow
stackoverflow.com › questions › 59934823 › meaning-of-null-definition-for-a-macro-in-c
linux - Meaning of NULL definition for a macro in C - Stack Overflow
January 27, 2020 - I was writing a simple code for accessing my driver data through entry in the procfs. While going through the header file proc_fs.h, I came across a macro like: #define proc_create(name, mode, parent, proc_fops) ({NULL;})
🌐
Threads
threads.com › @fab.ico › post › DH2e81HIV5W › null-is-a-cc-macro-it-depends-on-the-language-but-in-programming-everything-has-
NULL is a C/C++ macro. It depends on the language, but in ...
March 30, 2025 - NULL is a C/C++ macro. It depends on the language, but in programming everything has to get a value and machine code doesn't know NULL. You normally choose 0, because the OS blocks 0x00 as address, which leads to a memory violation error.
Top answer
1 of 3
4

There's probably some subtle reason that could be used to justify the difference, but I expect there's just no demand for a macro for the zero character (named NUL in ASCII).

NULL can be any null pointer constant of the implementation's choosing, it might be an integer or a pointer. So it's used when you need a null pointer constant, but you don't want to give readers the impression that it matters exactly which null pointer constant is used. Basically, you can use it to initialize/assign a pointer, when you want it to be a null pointer. You can also use it when testing whether a pointer is null.

Not everyone bothers using NULL. 0 is a permitted value of NULL, so anywhere that you can portably use NULL, you can use 0 instead. Personally I don't think the C language would be any poorer if it didn't have NULL. In particular, you can get into trouble passing NULL in a varargs function, because people generally think it's a pointer, and it converts to a pointer if required, but varargs functions don't convert it. So if it's not a pointer where a pointer is needed then you get UB. The same applies to functions without a prototype in scope.

The macro you propose would always expand to an int with value 0. "We need more ways of writing zero" doesn't seem to me the kind of thing that would excite the C standard committee to take action, even if it was proposed. If there was a set of macros naming the characters in the basic execution set, then having one for NUL in that set would make sense. But people seem happy to write 'a' instead of LATIN_LOWERCASE_A, '\n' instead of LINEFEED, and 0 or '\0' instead of NUL.

2 of 3
2

A macro has to expand to something that is not a macro. It's not turtles all the way down.

🌐
Embedded Artistry
embeddedartistry.com › home › blog › migrating from c to c++: null vs nullptr
Migrating from C to C++: NULL vs nullptr - Embedded Artistry
December 15, 2021 - The general rule of thumb that ... NULL, anyway? Traditionally, the NULL macro is an implementation defined constant representing a null pointer, usually the integer 0....
🌐
Microchip
onlinedocs.microchip.com › oxy › GUID-471BA167-B55F-488B-A1CC-D88BAA7832CA-en-US-4 › GUID-C2E5613D-3393-499E-9B3B-12072E59065C.html
25.3.16 The NULL Macro - Microchip Online docs
The NULL macro is defined by <stddef.h>; however, its definition is implementation-defined behavior. Under the CCI, the definition of NULL is the expression (0).
🌐
Microchip
onlinedocs.microchip.com › oxy › GUID-C4E60FF5-3DAB-44F1-BA61-4BD962D8F469-en-US-4 › GUID-C2E5613D-3393-499E-9B3B-12072E59065C.html
24.3.16 The NULL Macro - Microchip Online docs
The NULL macro is defined by <stddef.h>; however, its definition is implementation-defined behavior. Under the CCI, the definition of NULL is the expression (0).
🌐
Handmade Network
hero.handmade.network › forums › code-discussion › t › 1292-null_define_in_c__c_differs! › 2
NULL Define in c & c++ differs?! | Handmade Network
June 16, 2016 - This can be (and typically is) implemented by a void* null pointer because void* will implicitly convert to any other pointer type. In C++ this is not longer possible because void* cannot implicitly convert to other pointer types anymore. So the C++ committee apparently decided to dictate how to implement the NULL macro by requiring that the NULL macro must be defined as 0.