Language linkage
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) | ||||||||
| 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:
- "C++" , die Standard-Sprachverknüpfung.
- "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:
-
Ddeklariert eine Variable, die zum globalen Gültigkeitsbereich gehört. -
Wenn
Ceine Variable deklariert, deklariertDebenfalls eine Variable. -
Wenn
Ceine Funktion deklariert, deklariertDebenfalls 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
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]