1

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?

12
  • 1
    No object will return &object as 0. Perhaps a computation or UB will. Commented Feb 15, 2022 at 23:05
  • By 0, do you mean a null pointer or a pointer whose bit representation is all zeros? Commented Feb 15, 2022 at 23:06
  • @Brian Null pointer. Updated. Commented Feb 15, 2022 at 23:07
  • @chux-ReinstateMonica Meaning that an object cannot be placed at address 0? If yes, then why? In order to satisfy "is guaranteed to compare unequal to a pointer to any object or function"? Commented Feb 16, 2022 at 0:50
  • @pmor Ding, ding, ding, you win the prize! Commented Feb 16, 2022 at 3:21

3 Answers 3

3

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.

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

3 Comments

If "a null pointer is guaranteed to compare unequal to a pointer to any object" and "any two null pointers shall compare equal", then a null pointer is not a pointer to object. (What is an object?) Or is null pointer a pointer to a hypothetical "null object"? Hence, "a postfix expression followed by the -> operator and an identifier" does not designate a member of a structure object. Hence, ((struct some_struct *)0)->first_member violates the semantics of the -> operator. How can you comment?
The best answer. Good last paragraph summary.
@pmor: The behavior of ((struct some_struct *)0)->first_member is not defined by the C standard. Some C implementations use it in their own code because the C implementation supports it, not because the C standard does.
3

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:

  1. 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.

  2. 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.

2 Comments

(struct some_struct *)0 is a null pointer and so fails "An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. 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." &(((struct some_struct *)0)->first_member) relies on non-standard behavior. Safe for an implementation to do, but not user code.
@chux-ReinstateMonica: It's been debated to death; but there's a greater bug in it, in that it assumes something else. But in fact it's easier to do than the other two ways I give for & to yield a NULL.
2

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.

1 Comment

A null pointer is different from a null pointer constant. This passage only says the result of converting a null pointer constant (which can be the source token 0) to a pointer type compares unequal to a pointer to any object or function. There can be other representations of null pointers, and this passage does not say that they compare unequal to a pointer to any object or function.

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.