Why does the int* p = &(*(&n)) code work correctly? I, representing myself as a compiler, reproduce the code like this:

  • &n : return the address of the variable n
  • *(&n) : return the number lying at this address
  • &(*(&n)) : return the address where the number we just temporarily calculated is stored (?)

How does the compiler know what the address of the expression *(&n) ?

  • 2
    no way: mov eax, OFFSET FLAT:n godbolt.org/g/DGEAzB - pavel
  • @pavel is possible in more detail? I do not know the assembler - AnatoliySultanov
  • simple - * & destroy each other - pavel
  • @pavel And how exactly is "destroyed"? I am writing a simple interpreter of my language with similarity of pointers, and I can not figure out how to implement this mutual destruction * and & - AnatoliySultanov
  • The address is translated into the pointer, the pointer is translated into the address. One operation adds an offset to indicate the value, the second, on the contrary, decreases the offset to get the pointer address. That is, if simple at all. - Alex Krass

1 answer 1

The error lies in the highlighted word of this sentence.

& (* (& n)): return the address where the number we just temporarily calculated is stored (?)

The fact is that according to, for example, the C ++ standard (5.3.1 Unary operators)

It can be used if it’s not necessary to do so.

no temporary object is created.

The same is written in the C standard (6.5.3.2 Address and indirection operators)

4 The unary * operator denotes indirection. If the function is a function designator; if it is a point, it is a designating object.

Also in this same section of standard C is written

3 The unary & operator yields the address of its operand. If the operand has type '' type '', the result has a type '' pointer to type ''. It is not clear that the operator has been omitted , except for the operator.

So the expression

 &(*(&n)) 

equivalent to the original expression

 &n 

subject to the above limitations.

Note. The limitations mentioned in the quotation are sometimes substantial. For example, the result of this C program where a bunch of operators is used &*

 #include <stdio.h> int main( void ) { int a[10]; printf( "sizeof( a ) = %zu\n", sizeof( a ) ); printf( "sizeof( &*a ) = %zu\n", sizeof( &*a ) ); return 0; } 

will be next

 sizeof( a ) = 40 sizeof( &*a ) = 4 

That is, the operand of the first sizeof operator is lvalue , while the operand of the second sizeof operator will already be rvalue due to the use of the bunch &* . [End of note]

In this regard, there is an amusing side effect. Since the functions in the expressions are converted to a pointer to the function, it is possible to write the function call, for example, in the following form

 #include <iostream> void f() { std::cout << "Hello, pointers!" << std::endl; } int main() { ( **********f )(); //^^^^^^^^^^^^^ return 0; } 

This technique is useful when your productivity is estimated by the number of characters typed in the program. :)

  • I read here ... It’s clear about the functions, but not about the expression in the topic. Now there is no compiler, I can not check, but what will happen? Can you describe the process? - selya
  • @Alexander What expression are you talking about, a function call ?, - Vlad from Moscow
  • No, about &(*(&n)) . - selya
  • @Alexander & n - gives the address of the variable n. You can think of int * tmp = & n; Applying dereferencing to the * p pointer, we again get n, that is, as written in the standard, lvalue, which refers to n. - Vlad from Moscow
  • Ah, got it. They really mutually destroy each other. True, this causes unnecessary calculations (maybe some compilers optimize this). - selya