¿Cómo es legal void * a = & a?

88

Considere el siguiente código C ++:

void* a = &a;

¿Por qué el compilador no se queja por usar un identificador no declarado?

Además, ¿qué considera el compilador que es la variable a? ¿Es un puntero a un objeto vacío o es un puntero a un void*puntero?

usuario2681063
fuente
6
Punto de declaración
Grijesh Chauhan
15
Debería mencionar por qué querría hacer esto: para obtener un puntero a la parte superior de la pila (desde donde puede jugar con todo tipo de cosas).
OrangeDog

Respuestas:

95

El alcance de la declaración de variables en C ++ puede ser bastante sorprendente:

void* a =               &a;
         ^~~~~~~~~~~~~~~~~
          a declared as `void*` from here on

Por lo tanto, &aes void**pero dado que cualquier tipo de puntero es implícitamente convertible a void*...

Matthieu M.
fuente
¿Cómo le asignaría un objeto útil?
user2681063
22
@ user2681063 a = &userfulObject?
Nikos C.
4
@MarkGarcia: Tenga en cuenta que void *a = a;sería UB si se declara localmente, de lo contrario está bien en el ámbito del espacio de nombres.
Nawaz
1
@TheodorosChatzigiannakis: Creo que lo es, sí.
Matthieu M.
1
Una cita de especificación estaría muy bien aquí.
Benjamin Gruenbaum
30

Es equivalente a

void* a;
a = &a;

Por tanto, aha sido declarado. Entonces aobtiene la dirección de aescrita a. Por tanto, es un puntero a un puntero vacío. (Aún no ha definido ningún objeto).

Stasik
fuente
9
Técnicamente, definiste un objeto. aen sí mismo es un objeto. (No todos los objetos tienen tipos definidos por el usuario en C ++)
MSalters
1
@MSalters ¿Qué es este 'objeto' del que hablas? : D
Gusdor
3
@Gusdor Solo podemos asumir lo que está más allá del vacío del horizonte de eventos.
Cole Johnson
Se llaman de manera diferente, sin embargo, el "efecto" es el mismo en este caso
Stasik
No son equivalentes en general, pero en este escenario lo son.
Lightness Races in Orbit
7

En void* a, ase declara como un puntero no a un voidtipo sino a "cualquier" tipo (caso especial). Se asigna una dirección (posición en la memoria) a, como a cualquier otra variable que se declare, por supuesto.

Después de eso, &ase evalúa la expresión para inicializar la variable (también a, pero esto no es relevante) recién declarada. El tipo de &aes "puntero a puntero a cualquier tipo", que es un caso especial de "puntero a cualquier tipo", totalmente compatible con el tipo de a. Ergo, no hay mensaje del compilador.

Corolario: no lo use void*si desea una verificación de tipo sólida. Todo se puede convertir en él. Todo lo contrario en sentido inverso, excepto por void*sí mismo (sería una excepción innecesaria que un tipo fuera incompatible consigo mismo).

Además, AFAIR, esto realmente proviene de C.

Mario Rossi
fuente