2013-05-13 11 views
8

Il mio caso è piuttosto semplice: voglio che il mio programma C++ gestisca i segnali Unix. Per fare ciò, glibc fornisce una funzione in signal.h chiamata sigaction, che si aspetta di ricevere un puntatore di funzione come secondo argomento.C collegamento per il puntatore di funzione passato alla libreria C

extern "C" 
{ 
void uponSignal(int); 
} 

void uponSignal(int) 
{ 
    // set some flag to quit the program 
} 

static 
void installSignalHandler() 
{ 
    // initialize the signal handler 
    static struct sigaction sighandler; 
    memset(&sighandler, 0, sizeof(struct sigaction)); 
    sighandler.sa_handler = uponSignal; 

    // install it 
    sigaction(SIGINT, &sighandler, nullptr); 
} 

La mia domanda è: è l'identificatore extern "C" legame necessario?

Domanda bonus: può suSignal essere dichiarato static?

+0

Alcuni compilatori semplicemente rifiuteranno di compilarlo se si rimuove 'extern" C "' perché il secondo argomento di sigaction ha il tipo sbagliato. In molti compilatori è un bug che non considerano la parte di collegamento del tipo di funzione. –

risposta

4

extern C è necessario solo se si esportano i simboli dal proprio binario o importati da un altro binario (in genere in entrambi i casi, una libreria condivisa), al fine di evitare il manomissione del nome.

Qui non è questo il caso, non stai collegando uponSignal attraverso vari binari in modo da non aver bisogno di extern C. Tutto quello che stai facendo è passare l'indirizzo della tua funzione a sigaction da una funzione che già conosce l'indirizzo di uponSignal dato che sono parte (apparentemente) della stessa unità di traduzione, o per lo meno dello stesso binario.

Domanda bonus: possibile uponSignal essere dichiarato static?

Certo, se vuoi. uponSignal non ha comunque bisogno del collegamento esterno.

+1

In realtà, ero più preoccupato per le ** chiamate alle convenzioni ** che per il manomissione dei nomi. – qdii

+2

Non dovresti. ;) Anche se le convenzioni di chiamata sono specifiche dell'implementazione (es. Al di fuori dell'ambito dello standard), non ho mai visto un compilatore che non abbia reso la convenzione di chiamata parte della firma della funzione in modo che il compilatore ti avvisasse se è sempre una mancata corrispondenza (che raramente accade comunque). – syam

6

La mia domanda è: è necessario lo specificatore di collegamento extern "C"?

Per la massima portabilità, sì; lo standard C++ garantisce solo l'interoperabilità con C tramite le funzioni dichiarate extern "C".

Praticamente no; gli ABI più sensibili (incluso l'ABI GNU utilizzato da glibc) utilizzeranno la stessa convenzione di chiamata per le funzioni C e C++ non membro (e membro statico), in modo che extern "C" sia necessario solo per condividere il nome della funzione tra le lingue.

Domanda bonus: può essere dichiarato statico? uponSignal?

Sì. Il collegamento esterno è necessario solo per accedere alla funzione in base al nome di altre unità di traduzione; non è necessario chiamare la funzione tramite un puntatore a funzione.

+0

Avresti una quotazione indietro "Lo standard C++ garantisce solo l'interoperabilità con C tramite la funzione dichiarata extern" C ""? – qdii

+1

@qdii: Non proprio; non c'è nulla che dice esplicitamente che non c'è garanzia, solo nulla che fornisce tale garanzia. 7.5/1 specifica che "Due tipi di funzione con collegamenti linguistici diversi sono tipi distinti anche se sono identici" e ha una nota che indica che "un particolare collegamento linguistico può essere associato [...] a una particolare convenzione di chiamata, ecc. ". –