Como void * a = & a é legal?

88

Considere o seguinte código C ++:

void* a = &a;

Por que o compilador não reclama por usar um identificador não declarado?

Além disso, o que o compilador considera ser a variável a? É um ponteiro para um objeto vazio ou é um ponteiro para um void*ponteiro?

user2681063
fonte
6
Ponto de declaração
Grijesh Chauhan
15
Deve mencionar porque você deseja fazer isso - para obter um ponteiro para o topo da pilha (a partir do qual você pode mexer em todos os tipos de coisas).
OrangeDog

Respostas:

95

O escopo da declaração de variáveis ​​em C ++ pode ser bastante surpreendente:

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

Portanto, &aé void**mas, uma vez que qualquer tipo de ponteiro é implicitamente conversível em void*...

Matthieu M.
fonte
Como eu atribuiria um objeto útil a isso?
user2681063
22
@ user2681063 a = &userfulObject?
Nikos C.
4
@MarkGarcia: Observe que void *a = a;seria UB se declarado localmente, caso contrário, está bem no escopo do namespace.
Nawaz
1
@TheodorosChatzigiannakis: Eu acredito que sim.
Matthieu M.
1
Uma citação específica seria muito bom aqui.
Benjamin Gruenbaum
30

É equivalente a

void* a;
a = &a;

Portanto, afoi declarado. Portanto, aobtém o endereço de aescrito em a. Portanto, é um ponteiro para um ponteiro vazio. (Você não definiu nenhum objeto ainda.)

Stasik
fonte
9
Tecnicamente, você definiu um objeto. aem si é um objeto. (Nem todos os objetos têm tipos definidos pelo usuário em C ++)
MSalters
1
@MSalters, de que 'objeto' você fala? : D
Gusdor
3
@Gusdor Só podemos assumir o que está além do vazio do horizonte de eventos.
Cole Johnson de
Eles são chamados de maneiras diferentes, no entanto, o "efeito" é o mesmo neste caso
Stasik de
Eles não são equivalentes em geral, mas neste cenário são.
Lightness Races in Orbit de
7

Em void* a, aé declarado como um ponteiro não para um voidtipo, mas para "qualquer" tipo (caso especial). Um endereço (posição na memória) é atribuído aa , como a qualquer outra variável sendo declarada, é claro.

Depois disso, a expressão &aé avaliada para inicializar a variável (também a, mas isso não é relevante) recém-declarada. O tipo de &aé "ponteiro para ponteiro para qualquer tipo", que é um caso especial de "ponteiro para qualquer tipo", totalmente compatível com o tipo dea . Portanto, nenhuma mensagem do compilador.

Corolário: não use void*se desejar uma verificação de tipo forte. Qualquer coisa pode ser convertida para ele. Exatamente o oposto na direção reversa, exceto paravoid* si mesmo (seria uma exceção desnecessária que um tipo fosse incompatível com ele mesmo).

Além disso, AFAIR isso realmente vem de C.

Mario rossi
fonte