How to write C/C++ code correctly when null pointer is not all bits zero

According to the C spec:

An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant. 55) 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.

So 0 is a null pointer constant. And if we convert it to a pointer type we will get a null pointer that might be non-all-bits-zero for some architectures. Next let’s see what the spec says about comparing pointers and a null pointer constant:

If one operand is a
pointer and the other is a null pointer constant, the null pointer
constant is converted to the type of the pointer.

Let’s consider (p == 0): first 0 is converted to a null pointer, and then p is compared with a null pointer constant whose actual bit values are architecture-dependent.

Next, see what the spec says about the negation operator:

The result of the logical negation operator ! is 0 if the value of its
operand compares unequal to 0, 1 if the value of its operand compares
equal to 0. The result has type int. The expression !E is equivalent
to (0==E).

This means that (!p) is equivalent to (p == 0) which is, according to the spec, testing p against the machine-defined null pointer constant.

Thus, you may safely write if (!p) even on architectures where the null pointer constant is not all-bits-zero.

As for C++, a null pointer constant is defined as:

A null pointer constant is an integral constant expression (5.19)
prvalue of integer type that evaluates to zero or a prvalue of type
std::nullptr_t. A null pointer constant can be converted to a pointer
type; the result is the null pointer value of that type and is
distinguishable from every other value of object pointer or function
pointer type.

Which is close to what we have for C, plus the nullptr syntax sugar. The behavior of operator == is defined by:

In addition, pointers to members can be compared, or a pointer to
member and a null pointer constant. Pointer to member conversions
(4.11) and qualification conversions (4.4) are performed to bring them
to a common type. If one operand is a null pointer constant, the
common type is the type of the other operand. Otherwise, the common
type is a pointer to member type similar (4.4) to the type of one of
the operands, with a cv-qualification signature (4.4) that is the
union of the cv-qualification signatures of the operand types. [ Note:
this implies that any pointer to member can be compared to a null
pointer constant. — end note ]

That leads to conversion of 0 to a pointer type (as for C). For the negation operator:

The operand of the logical negation operator ! is contextually
converted to bool (Clause 4); its value is true if the converted
operand is true and false otherwise. The type of the result is bool.

That means that result of !p depends on how conversion from pointer to bool is performed. The standard says:

A zero value, null pointer value, or null member pointer value is
converted to false;

So if (p==NULL) and if (!p) does the same things in C++ too.

Leave a Comment