O que && significa em void * p = && abc;

102

Me deparei com um pedaço de código void *p = &&abc;. Qual é o significado &&disso? Eu sei sobre referências de rvalue, mas acho que &&usado neste contexto é diferente. O que &&indica em void *p = &&abc;?

Brent Arias
fonte
14
Onde você viu isso?
user541686
3
Eu também gostaria de saber onde você viu isso.
Flavius

Respostas:

154

&&é a extensão do gcc para obter o endereço do rótulo definido na função atual.

void *p = &&abc é ilegal em C99 e C ++ padrão.

A compila com g ++.

Prasoon Saurav
fonte
42
Agora imagine como todos seriam melhores programadores se o gcc tivesse -pedantic por padrão. Então as pessoas aprenderiam C em vez de informações irrelevantes sobre gnus.
Lundin
4
Que hack. Se eles inventarem uma nova sintaxe para ponteiros de rótulo, eles também devem inventar um novo tipo para ela em vez de usar void*.
Mark Ransom
1
@Prasoon Saurav: Quem votou negativamente provavelmente desaprova o recurso e está descontando em você.
Chuck
@Lundin: O mesmo pode ser dito da maioria dos compiladores. __forceinline? __declspec(naked)? Um dos meus MSVCismos favoritos é:, template<typename T> class X { friend T; }que é inválido C ++ 03.
Sebastian Mach
O segundo link está morto.
Cœur
96

Como descobrir

Esse é o endereço de um rótulo e é um recurso específico do GCC .

int main(void) {
    void* startp;
s:
    startp = &&s;
    printf("the assignment above starts at address %p\n", startp);
    return 0;
}

Você poderia ter descoberto sozinho testando:

int main(void) {
    void* startp;
    int a;
    startp = &&a;
    printf("startp=%p\n", startp);
    return 0;
}

Nesse caso, o GCC diz:

erro: rótulo 'a' usado, mas não definido

Sob o capô - montagem

Você precisa conhecer o assembler para realmente entender isso, mas tentarei explicar o que significa o endereço de um rótulo.

Depois que o SO carrega o arquivo .exe do disco, um componente do sistema operacional chamado "o carregador" (o Windows tem o "PE Loader", o linux tem o "ELF loader" ou talvez até outros, se estiverem compilados no kernel), ele faz uma "virtualização" desse programa, transformando-o em um processo.

Este processo pensa que é o único na RAM e tem acesso a toda a RAM (ou seja, 0x00000000-0xFFFFFFFF em uma máquina de 32 bits).

(o texto acima é apenas uma breve visão geral do que está acontecendo, você realmente precisa aprender a montagem para entendê-lo totalmente, então tenha paciência comigo)

Agora, o rótulo em um código-fonte é basicamente um endereço. "goto label;" não faz nada mais do que um salto para aquele endereço (pense no ponteiro de instrução no assembly). Esta etiqueta armazena esse endereço de RAM e é assim que você pode descobrir esse endereço.

Depois de aprender ASM, você perceberá que esse endereço aponta para uma instrução dentro da .textseção do executável. A .textseção é aquela que contém o código (binário) do programa a ser executado.

Você pode inspecionar isso com:

objdump -x a.out

Um exemplo prático

Conforme descrito no GCC , você pode usar isso para inicializar uma tabela de salto. Alguns geradores de scanner como o re2c (consulte o -gparâmetro) usam isso para gerar scanners mais compactos. Talvez haja até mesmo um gerador de analisador que utiliza a mesma técnica.

Flavius
fonte
4
Compile com -std = c99 -pedantic.
Lundin
2
É muito importante mencionar que é uma extensão do GCC, e não uma parte central da linguagem
jalf
1
Isso é impressionante, Flavius.
Octavian A. Damiean
1
Eu gosto desse tipo de resposta, mais pessoas precisam ser ensinadas a encontrar as respostas, em vez de apenas ouvir.
Letseatlunch
1
Obrigado pela explicação detalhada. Apreciei a análise relacionada à Montagem.
CᴴᴀZ de