7

The expresssion (void *)0 is called a null pointer. But how about the following:

int i = 0;
void *s = (void *)i;

Is s also a null-pointer? The C-language standard says:

6.3.2.3 Pointers

3 An integer constant expression with the value 0, such an expression cast to type void *, or the predefined constant nullptr is called a null pointer constant70). If a null pointer constant or a value of the type nullptr_t (which is necessarily the value nullptr) 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.

4 Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.

5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might produce an indeterminate representation when stored into an object.71)

According to this s would not be a null pointer?

4
  • 1
    The C FAQ 5.18 asks "Is a run-time integral value of 0, cast to a pointer, guaranteed to be a null pointer?" and answers "No". So, it would seem I'm wrong. I'd be curious if someone identifies a current machine where it doesn't work, but apparently, in theory, the result of casting an integer variable containing zero does not need to be a null pointer. (Minor caveat: the C FAQ was written in the previous millennium — but the rules probably haven't changed.) Commented Jun 6, 2024 at 5:23
  • 1
    @JonathanLeffler One example that has object pointers with the integral value of zero is the common Keil C(x)51 compiler for the MCU 8051 family, a widely used Harvard architecture. A zero function pointer points to the reset code. A zero generic pointer points to the DATA cell at address 0 of the internal RAM. A zero memory specific pointer points to the respective memory cell at address 0 of that memory. Commented Jun 6, 2024 at 6:49
  • @JonathanLeffler However, Keil C(x)51 is not a compliant compiler. :-D Because of its implementation, there is no chance to have a compliant NULL, except for generic pointers in principle. But to my knowledge, Keil did not take the opportunity. Commented Jun 6, 2024 at 6:50
  • @JonathanLeffler Plenty of microcontrollers have memory mapped registers at address zero (for example all of the Motorola-flavoured ones) - you'll have something like #define REGNAME (*(volatile uint8_t*)0) and that's used to access a register, not as a null pointer. Commented Jun 20, 2024 at 11:58

2 Answers 2

10

It will be on any typical modern system, but it doesn't have to be. Nothing in the standard requires pointer casts to behave the same for constant expressions and non-constant expressions.

The standard rationale document makes this explicit. From the C99 Rationale, Revision 5.10, 6.3.2.3:

Since pointers and integers are now considered incommensurate, the only integer value that can be safely converted to a pointer is a constant expression with the value 0. The result of converting any other integer value, including a non-constant expression with the value 0, to a pointer is implementation-defined.

Sign up to request clarification or add additional context in comments.

Comments

0

The expresssion (void *)0 is called a null pointer.

It is not. It is called a null pointer constant, a particular language item that may come either in the form of (void*)0 or 0 and is used for the purpose of turning an object/function pointer into a null pointer. Check out What's the difference between null pointers and NULL?

Is s also a null-pointer?

It is not, since a null pointer may only be formed from null pointer constants. The relevant part of the C standard is indeed the quoted 6.3.2.3. Note integer constant expression. (void *)i is not an integer constant expression.

The whole reason why null pointers are made something mysterious in C is because the "well-defined nowhere" could be anywhere in the memory map, highly system-dependent. The idea is that once you assign something to a null pointer constant, the resulting null pointer could in theory have any other representation than "all zeroes" internally.

For example int* ptr = 0; could in theory result in ptr containing the value 0xFFFFFFFF or something like that - the compiler should then swoop in and assign that raw representation "between the lines" whenever it detects a null pointer constant assignment.

In practice however, compilers for systems where 0 is a valid address normally don't do this, but rather use the representation of a null pointer as 0. I've had bugs like that on microcontroller systems where an accidental assignment to a null pointer caused GPIO activation. Quite dangerous, obviously.

There are supposedly some ISA that are actually designed for C in mind, using address 0 for the null pointer representation, but treating writes to that address as a software exception/trap. Or in case of virtual memory mapping, the MMU could make address 0 invalid.

5 Comments

The standard requires certain operations to produce null pointers, but it doesn't prohibit other operations from also producing null pointers. Casting non-constant integers to a pointer type is implementation-defined, and most implementations define it in such a way that casting a non-constant 0 to pointer type makes a null pointer.
Also see 6.5.9p6, which mandates that a null pointer cannot compare equal to any pointer other than another null pointer. If an implementation says that (int*)0 and (int*)x compare equal, where x is 0, then (int*)x must be a null pointer on this implementation.
@user2357112 There's nothing substantial in the C standard allowing a null pointer to get created like that. That's not implementation-defined, it's non-standard language extensions. As for (int*)0 it is not guaranteed to result in a null pointer since the standard explicitly says that 0 must be cast to a void* to result in a null pointer constant. Also as mentioned in this answer, lots of compilers do not treat null pointers as intended but just as address 0. This is a very confused part of the language overall, always was - the rationales for null pointers are all over the place.
0 is already a null pointer constant. You misread that section. There are 3 options for a null pointer constant: "An integer constant expression with the value 0, such an expression cast to type void *, or the predefined constant nullptr". 0 falls under the first option. Since 0 is a null pointer constant, (int*)0 must be a null pointer.
@user2357112 Ah yeah fair enough. Anyway, I can't think of any compiler or system that would treat null pointers different than object pointers with address zero. There's probably some archaic oddball ones that make the exception.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.