Namespaces
Variants

Language linkage

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Ermöglicht die Verknüpfung zwischen Programmeinheiten, die in verschiedenen Programmiersprachen geschrieben sind.

Dies kann auch verwendet werden, um eine Deklaration von ihrem Modul zu trennen. Siehe Module ownership .

(since C++20)
extern string-literal { declaration-seq  (optional) } (1)
extern string-literal declaration (2)
1) Wendet die Sprachspezifikation string-literal auf alle Funktionstypen, Funktionsnamen mit externer Verknüpfung und Variablen mit externer Verknüpfung an, die in declaration-seq deklariert sind.
2) Wendet die Sprachspezifikation string-literal auf eine einzelne Deklaration oder Definition an.
string-literal - ein unevaluated string literal , der die erforderliche Sprachbindung benennt
declaration-seq - eine Folge von Deklarationen, die geschachtelte Bindungsangaben enthalten kann
declaration - eine Deklaration

Inhaltsverzeichnis

Erklärung

Jeder Funktionstyp, jeder Funktionsname mit externer Verknüpfung und jeder Variablenname mit externer Verknüpfung besitzt eine Eigenschaft namens Sprachverknüpfung . Sprachverknüpfung kapselt die Anforderungen, die notwendig sind, um mit einer in einer anderen Programmiersprache geschriebenen Programmeinheit zu verknüpfen: Aufrufkonvention , Name Mangling (Namensdekoration) Algorithmus, usw.

Nur zwei Sprachverknüpfungen sind garantiert unterstützt:

  1. "C++" , die Standard-Sprachverknüpfung.
  2. "C" , die es ermöglicht, mit Funktionen zu verknüpfen, die in der Programmiersprache C geschrieben sind, und in einem C++-Programm Funktionen zu definieren, die aus in C geschriebenen Einheiten aufgerufen werden können.
extern "C"
{
    int open(const char *path_name, int flags); // C-Funktionsdeklaration
}
int main()
{
    int fd = open("test.txt", 0); // ruft eine C-Funktion aus einem C++-Programm auf
}
// Diese C++-Funktion kann aus C-Code aufgerufen werden
extern "C" void handler(int)
{
    std::cout << "Callback invoked\n"; // Kann C++ verwenden
}

Da Sprachverknüpfung Teil jedes Funktionstyps ist, behalten auch Zeiger auf Funktionen die Sprachverknüpfung bei. Sprachverknüpfung von Funktionstypen (die die Aufrufkonvention repräsentiert) und Sprachverknüpfung von Funktionsnamen (die das Name Mangling repräsentiert) sind voneinander unabhängig:

extern "C" void f1(void(*pf)()); // deklariert eine Funktion f1 mit C-Linkage,
                             // die void zurückgibt und einen Zeiger auf eine C-Funktion nimmt
                             // die void zurückgibt und keine Parameter akzeptiert
extern "C" typedef void FUNC(); // deklariert FUNC als einen C-Funktionstyp, der void zurückgibt
                                // und keine Parameter akzeptiert
FUNC f2;            // der Name f2 hat C++-Linkage, aber sein Typ ist C-Funktion
extern "C" FUNC f3; // der Name f3 hat C-Linkage und sein Typ ist C-Funktion void()
void (*pf2)(FUNC*); // der Name pf2 hat C++-Linkage, und sein Typ ist
                    // "Zeiger auf eine C++-Funktion, die void zurückgibt und ein
                    // Argument vom Typ 'Zeiger auf die C-Funktion, die void zurückgibt
                    // und keine Parameter akzeptiert' annimmt"
extern "C"
{
    static void f4(); // der Name der Funktion f4 hat interne Verknüpfung (keine Sprachbindung)
                      // aber der Funktions-Typ hat C-Sprachbindung
}

Wenn zwei Deklarationen einer Entität ihr unterschiedliche Sprachverknüpfungen zuweisen, ist das Programm fehlerhaft; keine Diagnose ist erforderlich, wenn keine der Deklarationen von der anderen erreichbar ist. Eine Neudeklaration einer Entität ohne Sprachverknüpfungsspezifikation erbt die Sprachverknüpfung der Entität und ihres Typs (falls vorhanden).

extern "C" int f();
extern "C++" int f(); // Fehler: Unterschiedliche Sprachverknüpfungen
extern "C" int g();
int g(); // OK, hat C-Sprachverknüpfung
int h(); // Hat standardmäßig C++-Sprachverknüpfung
extern "C" int h(); // Fehler: Unterschiedliche Sprachverknüpfungen

Spezielle Regeln für "C" Linkage

Wenn Klassenmitglieder , Friend-Funktionen mit einer nachgestellten requires -Klausel , (seit C++20) oder nicht-statische Memberfunktionen in einem "C" -Sprachblock erscheinen, bleibt die Verknüpfung ihrer Typen "C++" (aber Parametertypen, falls vorhanden, bleiben "C" ):

extern "C"
{
    class X
    {
        void mf();           // die Funktion mf und ihr Typ haben C++-Sprachbindung
        void mf2(void(*)()); // die Funktion mf2 hat C++-Sprachbindung;
                             // der Parameter hat den Typ "Zeiger auf C-Funktion"
    };
}
template<typename T>
struct A { struct B; };
extern "C"
{
    template<typename T>
    struct A<T>::B
    {
        friend void f(B*) requires true {} // C-Sprachbindung ignoriert
    };
}
namespace Q
{
    extern "C" void f(); // nicht fehlerhaft
}

Sei C eine Deklaration, die eine Funktion oder Variable mit "C" Sprachbindung deklariert. Falls eine andere Deklaration D eine Entität mit demselben Namen deklariert und eine der folgenden Bedingungen erfüllt, deklarieren C und D dieselbe Entität:

  • D deklariert eine Variable, die zum globalen Gültigkeitsbereich gehört.
  • Wenn C eine Variable deklariert, deklariert D ebenfalls eine Variable.
  • Wenn C eine Funktion deklariert, deklariert D ebenfalls eine Funktion.

Im Gegensatz zu regulären Neudeklarationen können C und D unterschiedliche Zielbereiche haben:

extern "C"
{
    int x;
    int f();
    int g() { return 1; }
}
namespace A
{
    int x;                // Fehler: Neudefinition von "x"
    int f();              // OK, Neudeklaration von "f"
    int g() { return 1; } // Fehler: Neudefinition von "g"
}

Allerdings gelten die Einschränkungen solcher Deklarationen weiterhin, was bedeutet, dass sie entweder beide Funktionen oder beide Variablen deklarieren sollten und die deklarierten Entitäten denselben Typ haben müssen:

namespace A
{
    extern "C" int x();
    extern "C" int y();
}
int x; // Fehler: Deklariert „x“ als eine andere Art von Entität neu
namespace B
{
    void y(); // Fehler: Deklariert „y“ mit einem anderen Typ neu
}

Hinweise

Sprachspezifikationen können nur im Namespace-Bereich erscheinen.

Die geschweiften Klammern der Sprachspezifikation begründen keinen Gültigkeitsbereich.

Wenn Sprachspezifikationen verschachtelt sind, ist die innerste Spezifikation diejenige, die wirksam ist.

Eine direkt in einer Sprachbindungsspezifikation enthaltene Deklaration wird so behandelt, als enthielte sie den extern Specifier für die Bestimmung der Linkage des deklarierten Namens und ob es sich um eine Definition handelt.

extern "C" int x; // eine Deklaration und keine Definition
// Die obige Zeile entspricht extern "C" { extern int x; }
extern "C" { int x; } // eine Deklaration und Definition
extern "C" double f();
static double f(); // Fehler: Linkage-Konflikt
extern "C" static void g(); // Fehler: Linkage-Konflikt

extern "C" ermöglicht es, Header-Dateien mit Deklarationen von C-Bibliotheksfunktionen in ein C++-Programm einzubinden. Wenn dieselbe Header-Datei jedoch mit einem C-Programm geteilt wird, muss extern "C" (was in C nicht erlaubt ist) mit einer entsprechenden #ifdef -Direktive ausgeblendet werden, typischerweise __cplusplus :

#ifdef __cplusplus
extern "C" int foo(int, int); // C++-Compiler sieht dies
#else
int foo(int, int);            // C-Compiler sieht dies
#endif

Der einzige moderne Compiler, der zwischen Funktionstypen mit "C" und "C++" Sprachbindungen unterscheidet, ist Oracle Studio. Andere erlauben keine Überladungen, die sich nur in der Sprachbindung unterscheiden, einschließlich der vom C++-Standard geforderten Überladungsmengen ( std::qsort , std::bsearch , std::signal , std::atexit und std::at_quick_exit ): GCC Bug 2316 , Clang Bug 6277 , CWG Issue 1555 .

extern "C"   using c_predfun   = int(const void*, const void*);
extern "C++" using cpp_predfun = int(const void*, const void*);
// fehlerhaft, wird jedoch von den meisten Compilern akzeptiert
static_assert(std::is_same<c_predfun, cpp_predfun>::value,
              "C- und C++-Sprachbindungen sollten Funktionsarten nicht unterscheiden.");
// die folgenden Deklarationen deklarieren in den meisten Compilern keine Überladungen
// da c_predfun und cpp_predfun als derselbe Typ betrachtet werden
void qsort(void* base, std::size_t nmemb, std::size_t size, c_predfun*   compar);
void qsort(void* base, std::size_t nmemb, std::size_t size, cpp_predfun* compar);

Schlüsselwörter

extern

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
CWG 4 C++98 Namen mit internem Linkage können Sprachlinkages haben beschränkt auf Namen mit externem Linkage
CWG 341 C++98 eine Funktion mit "C" Sprachlinkage kann
denselben Namen wie eine globale Variable haben
das Programm ist in diesem Fall fehlerhaft
(keine Diagnose erforderlich, wenn sie
in verschiedenen Übersetzungseinheiten erscheinen)
CWG 564 C++98 das Programm war fehlerhaft, wenn zwei Deklarationen
sich nur in Sprachlinkage-Spezifikationen unterschieden
(d.h. verschiedene Zeichenkettenliterale nach 'extern')
die tatsächlichen Sprachlinkages der
Deklarationen werden stattdessen verglichen
CWG 2460 C++20 Friend-Funktionen mit einer nachgestellten requires Klausel
und "C" Sprachlinkage hatten Konfliktverhalten
"C" Sprachlinkage
wird in diesem Fall ignoriert
CWG 2483 C++98 der Linkage der Typen statischer Memberfunktionen
in "C" Sprachblöcken war "C++"
der Linkage ist "C"

Referenzen

  • C++23-Standard (ISO/IEC 14882:2024):
  • 9.11 Linkage specifications [dcl.link]
  • C++20-Standard (ISO/IEC 14882:2020):
  • 9.11 Linkage specifications [dcl.link]
  • C++17-Standard (ISO/IEC 14882:2017):
  • 10.5 Linkage specifications [dcl.link]
  • C++14-Standard (ISO/IEC 14882:2014):
  • 7.5 Verbindungsspezifikationen [dcl.link]
  • C++11 Standard (ISO/IEC 14882:2011):
  • 7.5 Linkage specifications [dcl.link]
  • C++03-Standard (ISO/IEC 14882:2003):
  • 7.5 Verknüpfungsspezifikationen [dcl.link]
  • C++98-Standard (ISO/IEC 14882:1998):
  • 7.5 Verbindungsspezifikationen [dcl.link]