Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

As the comp.lang.c FAQ says, there are architectures where the null pointer is not all bits zero. So the question is what actually checks the following construction:

void* p = get_some_pointer(); if (!p)     return; 

Am I comparing p with machine dependent null pointer or I'm comparing p with arithmetic zero?

Should I write

void* p = get_some_pointer(); if (NULL == p)     return; 

instead to be ready for such architectures or is it just my paranoia?

like image 375
ivaigult Avatar asked Aug 21 '15 08:08

ivaigult


People also ask

Can I use 0 instead of null in C?

NULL is use as an abstraction because at the time it was not clear what the value of NULL would be from system to system. So the standard value is zero, Which is the same for '0'. Using NULL or '0' you are sure your code would work on any system regardless of what their values are.

Can a pointer be null in C?

A null pointer is a pointer which points nothing. Some uses of the null pointer are: a) To initialize a pointer variable when that pointer variable isn't assigned any valid memory address yet.

How do you declare null in C?

In practice, NULL is a constant equivalent to 0 , or "\0" . This is why you can set a string to NULL using: char *a_string = '\0'; Download my free C Handbook!


2 Answers

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.

like image 179
ivaigult Avatar answered Oct 14 '22 14:10

ivaigult


It doesn't matter if null pointer is all-bits zero or not in the actual machine. Assuming p is a pointer:

if (!p)  

is always a legal way to test if p is a null pointer, and it's always equivalent to:

if (p == NULL) 

You may be interested in another C-FAQ article: This is strange. NULL is guaranteed to be 0, but the null pointer is not?


Above is true for both C and C++. Note that in C++(11), it's preferred to use nullptr for null pointer literal.

like image 30
Yu Hao Avatar answered Oct 14 '22 15:10

Yu Hao