Was bewirkt das Einfügen von extern "C"
in C++-Code genau?
Zum Beispiel:
extern "C" {
void foo();
}
Was bewirkt das Einfügen von extern "C"
in C++-Code genau?
Zum Beispiel:
extern "C" {
void foo();
}
Ich habe zuvor 'extern "C"' verwendet für DLL (Dynamic Link Library) Dateien, um die main() Funktion "exportierbar" zu machen, damit sie später in einem anderen ausführbaren Programm aus der DLL verwendet werden kann. Vielleicht ist ein Beispiel hilfreich, wo ich es verwendet habe.
DLL
#include
#include
using namespace std;
#define DLL extern "C" __declspec(dllexport)
//Ich habe DLL für die dllexport Funktion definiert
DLL main ()
{
MessageBox(NULL,"Hallo von der DLL","DLL",MB_OK);
}
EXE
#include
#include
using namespace std;
typedef LPVOID (WINAPI*Function)();//macht ein Platzhalter für Funktion aus der DLL
Function mainDLLFunc;//macht eine Variable für den Funktionsplatzhalter
int main()
{
char winDir[MAX_PATH];//wird den Pfad der obigen DLL halten
GetCurrentDirectory(sizeof(winDir),winDir);//DLL ist im selben Verzeichnis wie die EXE
strcat(winDir,"\\beispiel.dll");//verknüpfe DLL-Namen mit Pfad
HINSTANCE DLL = LoadLibrary(winDir);//lade die Beispiel-DLL
if(DLL==NULL)
{
FreeLibrary((HMODULE)DLL);//wenn das Laden fehlschlägt, beende das Programm
return 0;
}
mainDLLFunc=(Function)GetProcAddress((HMODULE)DLL, "main");
//definierte Variable wird verwendet, um eine Funktion aus der DLL zuzuweisen
//GetProcAddress wird verwendet, um die Funktion mit dem vordefinierten externen Namen "DLL" und passendem Funktionsnamen zu finden
if(mainDLLFunc==NULL)
{
FreeLibrary((HMODULE)DLL);//wenn es fehlschlägt, beende das Programm
return 0;
}
mainDLLFunc();//führe die exportierte Funktion aus
FreeLibrary((HMODULE)DLL);
}
Falsch. extern "C"
und __declspec(dllexport)
sind nicht miteinander verbunden. Ersteres steuert Symboldekoration, letzteres ist für das Erstellen eines Exporteintrags verantwortlich. Sie können ein Symbol genauso gut mit C++-Namendekoration exportieren. Abgesehen davon, dass der Punkt dieser Frage völlig verfehlt wird, gibt es auch andere Fehler im Codebeispiel. Zum einen deklariert main
, das aus Ihrer DLL exportiert wird, keinen Rückgabewert. Oder den Aufrufkonvention. Beim Importieren verwenden Sie eine zufällige Aufrufkonvention (WINAPI
) und verwenden das falsche Symbol für 32-Bit-Builds (sollte _main
oder _main@0
sein). Entschuldigung, -1.
Tatsächlich handelt es sich nur um ein Arbeitsbeispiel, das ich zuvor verwendet habe, um die Exportfunktion zu erklären, und es sollte nur dazu dienen, eine Vorstellung davon zu bekommen, wie es verwendet werden kann. Ich habe nicht gesagt, dass es notwendig ist, es auf diese Weise zu verwenden. Außerdem ist die in der DLL deklarierte DLL-Hauptfunktion () vom Typ DLL, der -> (extern "C" __declspec(dllexport)) ist, nicht int oder string, wie oben definiert, und gibt nichts zurück wie void. Ich habe es "main" genannt, aber es kann beliebig benannt werden und sollte nicht mit dem "main" vom Typ int im ausführbaren Programm verwechselt werden. Trotzdem lässt sich dies problemlos kompilieren und funktioniert gut mit vielen anderen Funktionen in der DLL mit Parametern und Rückgabewert.
Das wiederholte, dass du nicht weißt, was du tust, aber auf diese Weise sieht es so aus, als ob es für dich, für eine nicht näher definierte Liste von Zielplattformen, funktioniert. Du hast nicht auf die Probleme reagiert, die ich in meinem vorherigen Kommentar angesprochen habe. Dies ist immer noch eine negative Bewertung, da es deutlich falsch ist (es gibt mehr, das nicht in einen einzigen Kommentar passte).
Diese Antwort ist für die Ungeduldigen / diejenigen, die Fristen einhalten müssen, unten steht nur ein Teil / eine einfache Erklärung:
Also
in C++ identifiziert die Namensverarbeitung jede Funktion eindeutig
in C identifiziert jede Funktion auch ohne Namensverarbeitung eindeutig
Um das Verhalten von C++ zu ändern, dh anzugeben, dass für eine bestimmte Funktion keine Namensverarbeitung erfolgen soll, können Sie extern "C" vor den Funktionsnamen verwenden, aus irgendeinem Grund, wie zum Exportieren einer Funktion mit einem bestimmten Namen aus einer DLL, zur Verwendung durch deren Client.
Lesen Sie andere Antworten, für detailliertere / korrektere Antworten.
Ein void f() Funktion, die von einem C-Compiler kompiliert wird, und eine Funktion mit dem gleichen Namen void f(), die von einem C++-Compiler kompiliert wird, sind nicht die gleiche Funktion. Wenn Sie diese Funktion in C geschrieben haben und dann versuchen, sie aus C++ heraus aufzurufen, würde der Linker nach der C++-Funktion suchen und nicht die C-Funktion finden.
extern "C" sagt dem C++-Compiler, dass Sie eine Funktion haben, die vom C-Compiler kompiliert wurde. Sobald Sie ihm gesagt haben, dass sie vom C-Compiler kompiliert wurde, weiß der C++-Compiler, wie er sie korrekt aufrufen soll.
Es ermöglicht dem C++-Compiler auch, eine C++-Funktion so zu kompilieren, dass der C-Compiler sie aufrufen kann. Diese Funktion wäre offiziell eine C-Funktion, aber da sie vom C++-Compiler kompiliert wird, kann sie alle C++-Funktionen verwenden und alle C++-Schlüsselwörter haben.
Beim Mischen von C und C++ (d.h., a. Aufrufen einer C-Funktion aus C++; und b. Aufrufen einer C++-Funktion aus C) verursacht das C++-Namensverwirrung Probleme beim Verknüpfen. Technisch gesehen tritt dieses Problem nur auf, wenn die aufgerufenen Funktionen bereits in Binärdateien kompiliert wurden (höchstwahrscheinlich eine *.a-Bibliotheksdatei) mit dem entsprechenden Compiler.
Also müssen wir extern "C" verwenden, um das Namensverwirrung in C++ zu deaktivieren.
Ohne andere gute Antworten zu konfliktieren, werde ich ein bisschen mein Beispiel hinzufügen.
Was genau macht der C++ Compiler: er verändert die Namen im Kompilierungsprozess, daher müssen wir dem Compiler sagen, dass er die Behandlung der C
-Implementierung speziell behandeln soll.
Wenn wir C++ Klassen erstellen und extern "C"
hinzufügen, sagen wir unserem C++ Compiler, dass wir die C-Aufrufkonvention verwenden.
Grund (wir rufen die C-Implementierung von C++ auf): entweder wollen wir eine C-Funktion von C++ aus aufrufen oder eine C++-Funktion von C aus aufrufen (C++ Klassen usw. funktionieren nicht in C).
Willkommen bei Stack Overflow. Wenn Sie sich entscheiden, eine ältere Frage zu beantworten, die gut etablierte und korrekte Antworten hat, kann es sein, dass Ihnen eine späte neue Antwort keinen Kredit einbringt. Wenn Sie über neue, einzigartige Informationen verfügen oder davon überzeugt sind, dass die anderen Antworten alle falsch sind, fügen Sie gerne eine neue Antwort hinzu, aber eine "schon wieder eine Antwort" mit denselben grundlegenden Informationen lange Zeit nach der Fragestellung wird Ihnen normalerweise nicht viel Kredit einbringen. Ehrlich gesagt, ich glaube nicht, dass es in dieser Antwort etwas Neues gibt.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
119 Stimmen
Ich möchte Ihnen diesen Artikel vorstellen: http://www.agner.org/optimize/calling_conventions.pdf Er erzählt Ihnen viel mehr über Aufrufkonventionen und die Unterschiede zwischen Compilern.