2166 Stimmen

Was bewirkt extern "C" in C++?

Was bewirkt das Einfügen von extern "C" in C++-Code genau?

Zum Beispiel:

extern "C" {
   void foo();
}

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.

4voto

SturmCoder Punkte 888

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

7 Stimmen

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.

0 Stimmen

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.

3 Stimmen

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).

4voto

Diese Antwort ist für die Ungeduldigen / diejenigen, die Fristen einhalten müssen, unten steht nur ein Teil / eine einfache Erklärung:

  • In C++ können Sie denselben Namen in einer Klasse überladen (zum Beispiel, da sie alle denselben Namen haben, können sie nicht einfach aus der DLL exportiert werden usw.). Die Lösung für diese Probleme besteht darin, sie in verschiedene Zeichenfolgen (sogenannte Symbole) umzuwandeln. Symbole umfassen den Funktionsnamen sowie die Argumente, so dass jede dieser Funktionen auch bei gleichem Namen eindeutig identifiziert werden kann (auch bekannt als Namensverarbeitung)
  • In C haben Sie keine Überladung, der Funktionsname ist eindeutig (somit ist keine separate Zeichenfolge zur eindeutigen Identifizierung eines Funktionsnamens erforderlich, daher ist das Symbol der Funktionsname selbst)

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.

4voto

gnasher729 Punkte 49452

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.

0 Stimmen

Der C++-Compiler kann eine extern "C" Funktion kompilieren - und (unter Einhaltung einiger Einschränkungen) wird sie von vom C-Compiler kompiliertem Code aufrufbar sein.

1voto

Trombe Punkte 183

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.

0voto

Susobhan Das Punkte 197

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).

0 Stimmen

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.com

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.

Powered by:

X