How can a variable take the address of itself within its own declaration?

Viewed 1817

Consider this:

void* x = &x;

printf("%p\n", x);

Surprisingly, it compiles and runs with the output:

7ffb2f7248

How is it possible for x to take the address of itself when x hasn't been created yet?

Edit: Note that in this case there is no ambiguity present in regards to it's assignment, making it clear as to what exactly is questioned.

5 Answers

C++ 2018 6.3.2 [basic.scope.pdecl] 1 says:

The point of declaration for a name is immediately after its complete declarator (Clause 11) and before its initializer (if any), except as noted below.

The “noted below” items do not apply here, so, in void* x = &x;, x is declared after the first x (which is the declarator) and before the = &x (the initializer), so x can be referred to in the initializer, essentially as if the code were void *x; x = &x;.

This answer is for the C-tag.

The expression:

void* x = &x;

is an init-declarator which is declarator = initializer

This can be found in section 6.7 of N1570 (draft C standard) and 6.7.6 says:

A full declarator is a declarator that is not part of another declarator. The end of a full declarator is a sequence point.

And 6.2.1/7 says:

Structure, union, and enumeration tags have scope that begins just after the appearance of the tag in a type specifier that declares the tag. ...<some text not quoted>... Any other identifier has scope that begins just after the completion of its declarator.

These sections tell that the object is created before it is initialized. Consequently, the initializer can use the address of the created objected.

In section 6.3.2.3 Pointers:

A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

Therefore - since any pointer can be converted to a void-pointer - the address of x can be assigned to a void-pointer.

So for your code:

First the object is created and then it is initialized.

void* x = &x;
^^^^^^^ ^^^^^  
   |      |
   |      step 2: initialize object
   |
   step 1: create object, i.e. end of full declarator

For this code it's pretty much the same as an assignment.

void* x; // Create
x = &x;  // Assignment instead of initialization
         // But in this case it works just the same

You are conflating allocation and initialization.

Storage is allocated for x simply because it is defined to exist by this declaration. Initialization is a separate step that follows allocation of storage. Because of this, the address of x can be known during its own initialization.

(Note that such a pointer cannot be safely dereferenced until the pointed-to value is done being initialized, but there is no reason why the address cannot be taken prior to initialization.)

How is it possible for x to take the address of itself when x hasn't been created yet?

Because an object doesn't need to exist in order to know where it will be created.

Very simple. Static storage duration objects address is known to the linker which fills all the addresses.

Automatic storage variables which are not optimized out and their address is used are easy for the compiler to calculate.

https://godbolt.org/z/e84xM3

Related