Domanda

ho scritto una funzione C ++ che ho bisogno di chiamare da un programma C. Per renderlo richiamabile da C, ho specificato extern "C" sulla funzione Dichiarazione . Poi ho compilato il codice C ++, ma il compilatore (Dignus Sistemi / C ++) generato un nome storpiato la funzione. Quindi, a quanto pare non ha onorato il extern "C".

Per risolvere questo, ho aggiunto extern "C" alla funzione definizione . Dopo questo, il compilatore generato un nome di funzione che è richiamabile da C.

Tecnicamente, l'extern "C" solo deve essere specificato nella dichiarazione di funzione. È giusto? (Il C ++ FAQ Lite ha un buon esempio di questo.) dovrebbe anche indicare sulla definizione di funzione?

Ecco un esempio per dimostrare questo:

/* ---------- */
/* "foo.h"    */
/* ---------- */

#ifdef __cplusplus
extern "C" {
#endif

/* Function declaration */
void foo(int);

#ifdef __cplusplus
}
#endif

/* ---------- */
/* "foo.cpp"  */
/* ---------- */

#include "foo.h"

/* Function definition */
extern "C"               // <---- Is this needed?
void foo(int i) {
  // do something...
}

Il mio problema potrebbe essere il risultato di codifica in modo errato qualcosa, o forse ho trovato un bug del compilatore. In ogni caso, ho voluto consultare StackOverflow per assicurarsi che io so che è tecnicamente il modo "giusto".

È stato utile?

Soluzione

Il 'extern "C"' non deve essere richiesta sulla funzione defintion fintanto che la dichiarazione ha e sta già visto nella compilazione del defintion. La norma prevede espressamente (7,5 / 5 specifiche Linkage):

  

Una funzione può essere dichiarata senza una specificazione sollevatore dopo un'esplicita specificazione legame è visto; il legame esplicitamente indicato nella dichiarazione precedente non è influenzata da una tale dichiarazione di funzione.

Tuttavia, generalmente rimetta il 'extern "C"' sul defintion pure, perché è in realtà una funzione con extern collegamento "C". Un sacco di gente odia quando non necessaria, roba ridondante è sulle dichiarazioni (come mettere virtual sul metodo override), ma io non sono uno di loro.

Altri suggerimenti

Modifica
Sembra come se avessi capito male la domanda. In ogni modo, ho provato:


// foo.cpp
/* Function definition */

#include "foo.h"

void foo(int i) {
 //do stuff
}
void test(int i)
{
// do stuff
}

// foo.h
#ifdef __cplusplus
extern "C" {
#endif

/* Function declaration */
void foo(int);

#ifdef __cplusplus
}
#endif

void test(int);

Utilizzando il comando nm per visualizzare i simboli dal file compilato:


linuxuser$ nm foo.o
00000006 T _Z4testi
         U __gxx_personality_v0
00000000 T foo

Questo suggerisce chiaramente che il nome della funzione dichiarata come extern "C" non è storpiato e la parola chiave extern "C" non è richiesto in definizione.
Se fosse necessario ogni codice della libreria C scritta senza extern "C" sarebbe stato inutilizzabile nei programmi C ++.

Proprio incontrato questa situazione ... Non una piacevole esperienza.

Il seguente è stato dichiarato in uno dei miei file c:

void unused_isr(void) {}
void ADC_IRQHandler(void)     __attribute__ ((weak, alias("unused_isr"))); 

Avanti da qualche parte in un file cpp ho definito:

void ADC_IRQHandler(void) {                                                                                  
    ...
}

E mi sono dimenticato di modificare la dichiarazione in avanti per:

void ADC_IRQHandler(void);

Mi c'è voluto un po 'prima ho capito che stavo facendo tutto a destra rispetto alla conversione AD, ma non è riuscito a aggiungere "extern C" per la definizione!

extern "C" void ADC_IRQHandler(void) {                                                                                  
    ...
}

Solo i miei due centesimi il motivo per cui potrebbe essere utile in determinate circostanze hanno l'abitudine di aggiungere alla definizione di pure.

Credo che questo deve essere chiarito qui, come ho appena avuto un problema simile e ci ho messo un po 'per ottenere questo chiaro nella mia testa, solo Brooks Moses toccato questo correttamente, e penso che debba essere dichiarato più chiaramente ...

In sintesi l'intestazione può buttare fuori, tutto il compilatore vede è il file cpp e se l'intestazione non è incluso con l'extern "C" nuovamente dentro la vostra cpp (che comunemente vedere), quindi l'extern "C" dovranno essere nel file cpp da qualche parte (sia nella definizione, o un'altra dichiarazione) in modo che il compilatore CXX può sapere di farlo con collegamento C, il compilatore non si preoccupa l'intestazione, solo il linker.

Il extern "C" intorno la definizione non è necessaria. Si può ottenere via con solo mettendo in giro la dichiarazione. Una nota nel tuo esempio ...

#ifdef __cplusplus
extern "C" {
#endif

/* Function declaration */
void foo(int);

#ifdef __cplusplus
}
#endif

Il codice è alla ricerca per la macro preprocessore "__cplusplus".

Mentre è comunemente implementato, a seconda del compilatore, questo può o non può essere definito. Nel tuo esempio, è possibile utilizzare anche extern "C" intorno alla dichiarazione, ma tant'è non il controllo per la macro "__cplusplus", che è il motivo per cui ho il sospetto che ha funzionato una volta che ha fatto.

Visualizza i commenti qui sotto -. Standard C ++ richiede la macro __cplusplus da definire dal preprocessore

Dovrebbe essere intorno a entrambi. Il compilatore ha bisogno di sapere di utilizzare il nome C simbolo e convenzioni di chiamata durante la compilazione dei siti di chiamata (che possono vedere solo una dichiarazione), e il compilatore deve anche sapere per generare il nome C simbolo e utilizzare le convenzioni di chiamata C durante la compilazione del funzione definizione stessa (che non può vedere qualsiasi altra dichiarazione).

Ora, se si dispone di una dichiarazione extern-C che è visibile dalla unità di traduzione in cui esiste la definizione, si può essere in grado di cavarsela con lasciando fuori la extern-C dalla definizione, ma non so per certo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top