2009-09-04 12 views
25

Ich schrieb eine C++ - Funktion, die ich aus einem C-Programm aufrufen muss. Um es von C abrufbar zu machen, spezifizierte ich extern "C" auf der Funktion Erklärung. Ich kompilierte dann den C++ Code, aber der Compiler (Dignus Systems/C++) erzeugte für die Funktion einen mangled name. Also, es offenbar nicht die extern "C".Wird extern "C" nur zur Funktionsdeklaration benötigt?

Um dies zu beheben, fügte ich extern "C" zu der Funktion Definition. Danach erzeugte der Compiler einen Funktionsnamen, der von C aufrufbar ist.

Technisch muss der extern "C" nur in der Funktionsdeklaration angegeben werden. Ist das richtig? (Die C++ FAQ Lite hat ein gutes Beispiel dafür.) Sollten Sie es auch in der Funktionsdefinition angeben?

Hier ist ein Beispiel, dies zu demonstrieren:

/* ---------- */ 
/* "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... 
} 

Mein Problem das Ergebnis falsch Codierung etwas kann, oder ich kann einen Compiler Fehler gefunden haben. In jedem Fall wollte ich stackoverflow abfragen, um sicherzugehen, dass ich weiß, was technisch der "richtige" Weg ist.

+4

Sind Sie sicher, dass Sie tatsächlich das Mangeln von foo bekommen, wenn Sie das externe "C" in foo.c in dem Beispielcode, den Sie anzeigen, weglassen? Oder war das nur etwas, das in einem anderen komplizierteren Code auftrat? Ich habe dieses Problem oft als Symptom des Vergessens gesehen, foo.h in foo.c. –

+0

@Brooks Moses: Das ist ein großer Punkt. In meinem eigentlichen Code, der etwas komplexer ist als dieses "foo" Beispiel, füge ich den Header in die Quelldatei "cpp" ein. Was mich dazu gebracht hat zu denken, dass der Compiler den Namen gemangelt hat, war folgender: Wenn ich das 'extern' C '' nicht in die Funktionsdefinition einbeziehe, dann zeigt die Compilerliste das externe Symbol "foo_FPFPCc_v". Wenn das 'extern' C '' enthalten ist, zeigt die Auflistung das externe Symbol, "foo". – bporter

+1

@bporter - es könnte interessant sein zu experimentieren mit dem, was der Compiler mit Ihrem vereinfachten Beispiel macht. Wenn es das gleiche Verhalten zeigt, möchten Sie möglicherweise eine Notiz an den Anbieter senden. Wenn dies nicht der Fall ist, sollten Sie herausfinden, was in Ihrem echten Build vor sich geht, da dies bedeuten würde, dass der falsche Header eingefügt wird (oder etwas anderes die Funktionsdeklaration verpasst). –

Antwort

29

Das 'extern "C"' sollte bei der Funktionsdefinition nicht benötigt werden, solange es in der Deklaration steht und bereits in der Definitionsdefinition zu sehen ist. Der Standard besagt ausdrücklich (7.5/5 Verbindungsspezifikationen):

Eine Funktion kann ohne Verbindungsspezifikation deklariert werden, nachdem eine explizite Verknüpfungsspezifikation gesehen wurde; Die in der früheren Deklaration explizit angegebene Verknüpfung ist von einer solchen Funktionsdeklaration nicht betroffen.

Allerdings habe ich im Allgemeinen setzen die ‚extern "C"‘ auf der Defintion als auch, weil es in der Tat eine Funktion mit extern „C“ Verknüpfung ist. Eine Menge Leute hassen, wenn unnötige, redundante Sachen auf Deklarationen sind (wie virtual bei Methodenüberschreibungen setzen), aber ich bin keiner von ihnen.

+0

@Michael Burr - Danke für Ihre Antwort. Es klingt so, als ob das 'externe' C '' für die Definition nicht benötigt wird, solange es in einer früheren Deklaration angegeben ist. Wie Sie bereits erwähnt haben, kann ich weitergehen und es an beiden Orten spezifizieren. (In der Tat, ich muss möglicherweise, bis ich herausfinden, dass mein Problem etwas anderes als ein Compiler-Fehler ist. Wenn es wie ein Compiler-Fehler aussieht, dann werde ich es dem Anbieter melden, damit sie sich damit befassen können.) – bporter

+0

Ich dachte, dass ich der einzige bin, der "virtual" Methodenüberschreibungen setzt :-) – Mawg

0

Es sollte um beide sein. Der Compiler muss wissen, dass er den C-Symbolnamen und die Aufrufkonventionen beim Kompilieren der Call-Sites verwendet (die nur eine Deklaration sehen können), und der Compiler muss auch den C-Symbolnamen generieren und beim Kompilieren die C-Aufrufkonventionen verwenden Funktionsdefinition selbst (die keine anderen Deklarationen sehen kann).

Nun, wenn Sie eine extern-C-Deklaration haben, die aus der Übersetzungseinheit, in der die Definition existiert, sichtbar ist, können Sie das externe-C von der Definition weglassen, aber ich nicht das sicher wissen.

+3

Dies ist in dem Fall falsch, wie beschrieben, wo foo.h in foo.c enthalten ist, und "wegkommen mit" ist irreführend für die Verwendung von Verhalten durch den Standard erforderlich. Wenn man foo.h in foo.c einfügt - wie man es ohnehin immer tun sollte, damit der Compiler überprüfen kann, ob die Deklaration tatsächlich korrekt ist! - dann gibt es keine Notwendigkeit (außer vielleicht Klarheit für Leser) - extern "C" auf die Definition innerhalb von foo.c. –

1

Bearbeiten:
Scheint wie ich die Frage missverstanden hatte. Sowieso habe ich versucht:


// 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); 

Befehl Mit nm die Symbole aus der kompilierte Datei anzuzeigen:


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

Dies zeigt eindeutig, dass der Name der Funktion als extern „C“ deklariert nicht verstümmelt und Das externe Schlüsselwort "C" wird bei der Definition nicht benötigt.
Wäre es erforderlich, dass jeder C-Bibliothekscode, der ohne extern geschrieben wurde, "C" in C++ - Programmen unbrauchbar gewesen wäre.

+0

@Neeraj - Danke für dein Beispiel. Das habe ich auch in meinem Fall erwartet. Es scheint, dass mein Compiler den Funktionsnamen "foo" manipuliert, es sei denn, ich gebe "extern" C "" für die Deklaration und die Definition an. Ich denke, dass Sie und einige der anderen Plakate richtig sind, dass das "externe" C "für die Definition nicht erforderlich ist, solange es in einer früheren Deklaration angegeben ist. – bporter

0

Die extern "C" um die Definition ist nicht erforderlich. Sie können damit davonkommen, es einfach um die Deklaration herum zu legen. Ein Hinweis in Ihrem Beispiel ...

#ifdef __cplusplus 
extern "C" { 
#endif 

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

#ifdef __cplusplus 
} 
#endif 

Ihr Code wird für den Präprozessormakro "__cplusplus" suchen.

Obwohl es häufig implementiert wird, kann dies abhängig von Ihrem Compiler definiert sein oder nicht. In Ihrem Beispiel verwenden Sie auch extern "C" um die Deklaration, aber dort sind nicht Überprüfung für die "__cplusplus" Makro, weshalb ich vermute, es funktioniert, sobald Sie das getan haben.

die Kommentare Siehe unten - Standard C++ erfordert die __cplusplus Makro durch den Präprozessor definiert werden.

+0

@whitej - Das Makro "__cplusplus" wird zufällig von meinem speziellen Compiler definiert, aber Sie haben recht, dass es nicht "Standard" ist. Außerdem benutze ich dieses Makro in der Kopfzeile, da ich hier die Funktion deklariere (und es ist die Stelle, wo die meisten Leute über die Schnittstelle lernen würden), und es erlaubt mir, die Kopfzeile in C- und C++ - Dateien einzuschließen. C-Compiler unterstützen nicht 'extern' C '', und dieses Makro fügt das 'externe' C '' nur dann ein, wenn es angemessen ist. Beachten Sie, dass das Makro in "foo.cpp" nicht benötigt wird, wenn "extern" C "angegeben ist, da" foo.cpp "immer von einem C++ - Compiler kompiliert wird. – bporter

+4

Das Makro "' __cplusplus' "wird vom Standard benötigt, um beim Kompilieren eines C++ Moduls definiert zu werden - es gibt absolut keine Probleme bei der Verwendung. –

+1

Und während das "' __cplusplus' "oft in den Headern benötigt wird (da sie von C- oder C++ - Modulen enthalten sein können), ist es normalerweise in .c oder .cpp-Dateien nicht notwendig, da sie normalerweise als C oder C++ kompiliert werden , aber nicht beides (es gibt natürlich Ausnahmen, aber normalerweise nicht). –

1

Gerade diese Situation angetroffen ... Keine angenehme Erfahrung.

Die folgende in einem meiner c Dateien deklariert wurde:

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

Next irgendwo in einer cpp Datei I definiert:

void ADC_IRQHandler(void) {                     
    ... 
} 

Und ich vergaß, um die Vorwärts-Erklärung zu ändern:

void ADC_IRQHandler(void); 

Es dauerte eine Weile, bis ich herausgefunden habe Ich habe alles richtig gemacht in Bezug auf die AD-Konvertierung, aber ich habe es versäumt, der Definition "extern C" hinzuzufügen!

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

Nur meine zwei Cents, warum es unter bestimmten Umständen nützlich sein könnte, die Gewohnheit zu haben, um es in die Definition als auch hinzuzufügen.

1

Ich denke, das muss hier geklärt werden, da ich gerade ein ähnliches Problem hatte und es eine Weile gedauert hat, dies in meinem Kopf klar zu machen, nur Brooks Moses hat das richtig angesprochen, und ich denke, es muss gesagt werden klarer ...

Zusammenfassend kann der Header Sie wegwerfen, alles, was der Compiler sieht, ist die cpp-Datei und wenn der Header nicht mit dem externen "C" zurück in Ihr cpp enthalten ist (was ich häufig sehe), dann muss das externe "C" irgendwo in der cpp-Datei sein (entweder in der Definition oder einer anderen Deklaration), damit der CXX-Compiler es mit C-Verknüpfung machen kann, der Compiler kümmert sich nicht um den Header, nur den Linker .