C2x, 6.5.3.2 Address and indirection operators, Semantics, 3:
The unary & operator yields the address of its operand.
A simple question: can the unary &
operator yield the address 0
(null pointer)?
Any examples / experience?
CodePudding user response:
It can. But you have to go out of your way to make it possible.
There are two ways to do this for an actual object:
Construct an object file or linker symbol file that you are linking against that exports a symbol at NULL. If you & on that you will get NULL.
Be libc on certain platforms. The first symbol you define is NULL. On at least one platform, the heap manager had to contend with this so it was carefully coded so the compiler would never observe the fact the heap HEAD pointer was stored at NULL.
Notice that both of these waaaay out of portable C, and that's the point. If you get &
to return NULL you will know you did it. It's not happening by accident.
However there is another way: We can construct an expression containing no real objects where &
returns a 0. Like this:
&(((struct some_struct *)0)->first_member)
Only seen in
#define offsetof(type, member) ((size_t)&(((type *)0)->member))
Don't do this. #include <stddef>
and let the compiler define offsetof
. There's a bug in this implementation.
CodePudding user response:
The relevant section of the standard is 6.3.2.3/3 (N2731), which states
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.
Consequently, the result of &
acting on any object is guaranteed to "compare unequal" with a null pointer.
CodePudding user response:
C 2018 6.5.3.2 1 says:
The operand of the unary
&
operator shall be either a function designator, the result of a[]
or unary*
operator, or an lvalue that designates an object that is not a bit-field…
If the operand is a function designator, it cannot be a null pointer, since C 2018 6.3.2.3 3 says a null pointer “is guaranteed to compare unequal to a pointer to any object or function,” but a function designator that were a null pointer would compare equal to another (possibly different) null pointer because C 2018 6.5.9 6 says two null pointers compare equal.
If it is an lvalue that designates an object, then it cannot be a null pointer, for the same reason. (Note that 6.5.3.2 1 specifically refers to an lvalue that designates an object. In general, an lvalue is an expression that potentially designates an object. That is, it must have an object type. However, the constraint in 6.5.3.2 1 specifically tells us the operand must actually designate an object.)
That leaves the result of []
or unary *
. The former is defined in terms of the latter, so we only need to consider unary *
. C 2018 6.5.3.2 2 says “The operand of the unary *
operator shall have pointer type,” but it does not require it to point to an actual object or function or to be non-null. 6.5.3.2 4 says “… If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object…” but does not explicitly say what the result is if the operand is a null pointer. It goes on to say “ If an invalid value has been assigned to the pointer, the behavior of the unary *
operator is undefined.” The text there refers to note 106, which says “… Among the invalid values for dereferencing a pointer by the unary *
operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.”
Therefore, there is no behavior defined by the C standard in which unary &
would yield a null pointer. It may, of course, happen through behavior not defined by the standard.