Cosa significa && in void * p = && abc;


102

Mi sono imbattuto in un pezzo di codice void *p = &&abc;. Qual è il significato di &&qui? Conosco i riferimenti rvalue ma penso che &&usati in questo contesto siano diversi. Cosa &&indica in void *p = &&abc;?


14
Dove l'hai visto?
user541686

3
Mi piacerebbe anche sapere dove l'hai visto.
Flavio

Risposte:


154

&&è l'estensione di gcc per ottenere l'indirizzo dell'etichetta definita nella funzione corrente.

void *p = &&abc è illegale nello standard C99 e C ++.

Questo si compila con g ++.


42
Ora immagina come sarebbero tutti programmatori migliori se gcc avesse -pedantic per impostazione predefinita. Quindi le persone imparerebbero C invece di informazioni irrilevanti su gnus.
Lundin

4
Che trucco. Se inventano una nuova sintassi per i puntatori di etichette, dovrebbero inventarne anche un nuovo tipo invece di usare void*.
Mark Ransom

1
@Prasoon Saurav: Chiunque abbia votato negativamente probabilmente disapprova la funzione e se la prende con te.
Chuck

@ Lundin: Lo stesso si può dire della maggior parte dei compilatori. __forceinline? __declspec(naked)? Uno dei miei MSVCisms preferiti è:, template<typename T> class X { friend T; }che non è C ++ 03 non valido.
Sebastian Mach

Il secondo anello è morto.
Cœur

96

Come scoprirlo

Questo è l'indirizzo di un'etichetta ed è una funzionalità specifica di GCC .

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

Avresti potuto capirlo da solo testando:

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

In tal caso GCC dice:

errore: etichetta "a" utilizzata ma non definita

Sotto il cofano - montaggio

Devi conoscere l'assemblatore per capirlo veramente, ma cercherò di spiegarti cosa significa un indirizzo di un'etichetta.

Dopo che il sistema operativo ha caricato il file .exe dal disco, un componente del sistema operativo chiamato "il caricatore" (Windows ha il "caricatore PE", linux ha "caricatore ELF" o forse anche altri, se sono compilati nel kernel), esegue una "virtualizzazione" di quel programma, trasformandolo in un processo.

Questo processo pensa che sia l'unico nella RAM e abbia accesso all'intera RAM (ovvero 0x00000000-0xFFFFFFFF su una macchina a 32 bit).

(quanto sopra è solo una breve panoramica di quello che sta succedendo, devi davvero imparare il montaggio per capirlo appieno, quindi abbi pazienza)

Ora, l'etichetta in un codice sorgente è fondamentalmente un indirizzo. "goto label;" non fa nient'altro che un salto a quell'indirizzo (pensa al puntatore dell'istruzione in assembly). Questa etichetta memorizza questo indirizzo RAM ed è così che puoi trovare quell'indirizzo.

Dopo aver appreso ASM, ti renderai conto che quell'indirizzo punta a un'istruzione all'interno della .textsezione dell'eseguibile. La .textsezione è quella che contiene il codice (binario) del programma da eseguire.

Puoi ispezionarlo con:

objdump -x a.out

Un esempio pratico

Come descritto in GCC , puoi usarlo per inizializzare una tabella di salto. Alcuni generatori di scanner come re2c (vedi il -gparametro) lo usano per generare scanner più compatti. Forse c'è anche un generatore di parser che utilizza la stessa tecnica.


4
Compila con -std = c99 -pedantic.
Lundin

2
Abbastanza importante menzionare che si tratta di un'estensione GCC e non una parte fondamentale del linguaggio
jalf

1
Questo è piuttosto impressionante Flavius.
Ottaviano A. Damiean

1
mi piace questo tipo di risposta, più persone hanno bisogno di imparare a trovare le risposte piuttosto che semplicemente sentirsi dire.
Pranzo

1
Grazie per la spiegazione approfondita. Ho apprezzato l'analisi relativa all'Assemblea.
CᴴᴀZ
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.