Sprachbindung
Ermöglicht die Bindung zwischen Programmeinheiten, die in verschiedenen Programmiersprachen geschrieben sind.
|
Dies kann auch verwendet werden, um eine Deklaration von ihrem Modul zu trennen. Siehe Modulbesitz. |
(seit C++20) |
extern string-literal { declaration-seq (optional) } |
(1) | ||||||||
extern string-literal declaration |
(2) | ||||||||
| string-literal | - | ein nicht ausgewertetes String-Literal, das die erforderliche Sprachbindung benennt |
| declaration-seq | - | eine Sequenz von Deklarationen, die verschachtelte Bindungsspezifikationen enthalten kann |
| Deklaration | - | eine Deklaration |
Inhalt |
[bearbeiten] Erklärung
Jeder Funktionstyp, jeder Funktionsname mit externer Bindung und jeder Variablenname mit externer Bindung hat eine Eigenschaft namens Sprachbindung. Sprachbindung kapselt die Menge der Anforderungen, die zur Verknüpfung mit einer in einer anderen Programmiersprache geschriebenen Programmeinheit erforderlich sind: Aufrufkonvention, Algorithmus für Namensverknüpfung (Namensverschönerung) usw.
Nur zwei Sprachbindungen werden garantiert unterstützt
- "C++", die Standard-Sprachbindung.
- "C", was die Verknüpfung mit in der C-Programmiersprache geschriebenen Funktionen ermöglicht und die Definition von Funktionen in einem C++-Programm, die von in C geschriebenen Einheiten aufgerufen werden können.
extern "C" { int open(const char *path_name, int flags); // C function declaration } int main() { int fd = open("test.txt", 0); // calls a C function from a C++ program } // This C++ function can be called from C code extern "C" void handler(int) { std::cout << "Callback invoked\n"; // It can use C++ }
Da die Sprachbindung Teil jedes Funktionstyps ist, behalten auch Funktionszeiger die Sprachbindung bei. Die Sprachbindung von Funktionstypen (die die Aufrufkonvention repräsentiert) und die Sprachbindung von Funktionsnamen (die die Namensverknüpfung repräsentiert) sind voneinander unabhängig
extern "C" void f1(void(*pf)()); // declares a function f1 with C linkage, // which returns void and takes a pointer to a C function // which returns void and takes no parameters extern "C" typedef void FUNC(); // declares FUNC as a C function type that returns void // and takes no parameters FUNC f2; // the name f2 has C++ linkage, but its type is C function extern "C" FUNC f3; // the name f3 has C linkage and its type is C function void() void (*pf2)(FUNC*); // the name pf2 has C++ linkage, and its type is // "pointer to a C++ function which returns void and takes one // argument of type 'pointer to the C function which returns void // and takes no parameters'" extern "C" { static void f4(); // the name of the function f4 has internal linkage (no language) // but the function's type has C language linkage }
Wenn zwei Deklarationen einer Entität ihr unterschiedliche Sprachbindungen geben, ist das Programm schlecht formuliert; keine Diagnose ist erforderlich, wenn keine Deklaration von der anderen erreichbar ist. Eine Neudeklaration einer Entität ohne Bindungsspezifikation erbt die Sprachbindung der Entität und ihres Typs (falls vorhanden).
extern "C" int f(); extern "C++" int f(); // Error: different language linkages extern "C" int g(); int g(); // OK, has C language linkage int h(); // has C++ language linkage by default extern "C" int h(); // Error: different language linkages
[bearbeiten] Sonderregeln für "C"-Bindung
Wenn Klassenmitglieder, friend-Funktionen mit einer nachfolgenden requires Klausel,(seit C++20) oder nicht-statische Member-Funktionen in einem "C"-Sprachblock vorkommen, bleibt die Bindung ihrer Typen "C++" (aber Parametertypen, falls vorhanden, bleiben "C")
extern "C" { class X { void mf(); // the function mf and its type have C++ language linkage void mf2(void(*)()); // the function mf2 has C++ language linkage; // the parameter has type “pointer to C function” }; } template<typename T> struct A { struct B; }; extern "C" { template<typename T> struct A<T>::B { friend void f(B*) requires true {} // C language linkage ignored }; } namespace Q { extern "C" void f(); // not ill-formed }
Sei C eine Deklaration, die eine Funktion oder Variable mit "C"-Sprachbindung deklariert. Wenn 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 Geltungsbereich 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 Ziel-Geltungsbereiche haben
extern "C" { int x; int f(); int g() { return 1; } } namespace A { int x; // Error: redefines “x” int f(); // OK, redeclares “f” int g() { return 1; } // Error: redefines “g” }
Die Beschränkungen solcher Deklarationen gelten jedoch 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; // Error: redeclares “x” as a different kind of entity namespace B { void y(); // Error: redeclares “y” with a different type }
[bearbeiten] Hinweise
Sprachspezifikationen dürfen nur im Namespace-Geltungsbereich erscheinen.
Die geschweiften Klammern der Sprachspezifikation bilden keinen Geltungsbereich.
Wenn Sprachspezifikationen verschachtelt sind, ist die innerste Spezifikation diejenige, die wirksam ist.
Eine Deklaration, die direkt in einer Sprachbindungsspezifikation enthalten ist, wird so behandelt, als enthielte sie den extern Spezifikator für die Bestimmung der Bindung des deklarierten Namens und ob es sich um eine Definition handelt.
extern "C" int x; // a declaration and not a definition // The above line is equivalent to extern "C" { extern int x; } extern "C" { int x; } // a declaration and definition extern "C" double f(); static double f(); // error: linkage conflict extern "C" static void g(); // error: linkage conflict
extern "C" ermöglicht das Einbinden von Header-Dateien mit Deklarationen von C-Bibliotheksfunktionen in ein C++-Programm. Wenn dieselbe Header-Datei jedoch mit einem C-Programm geteilt wird, muss extern "C" (das in C nicht erlaubt ist) mit einem entsprechenden #ifdef ausgeblendet werden, typischerweise __cplusplus
#ifdef __cplusplus extern "C" int foo(int, int); // C++ compiler sees this #else int foo(int, int); // C compiler sees this #endif
Der einzige moderne Compiler, der 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 erforderlichen Überladungsmengen (std::qsort, std::bsearch, std::signal, std::atexit und std::at_quick_exit): GCC-Fehler 2316, Clang-Fehler 6277, CWG-Problem 1555.
extern "C" using c_predfun = int(const void*, const void*); extern "C++" using cpp_predfun = int(const void*, const void*); // ill-formed, but accepted by most compilers static_assert(std::is_same<c_predfun, cpp_predfun>::value, "C and C++ language linkages shall not differentiate function types."); // following declarations do not declare overloads in most compilers // because c_predfun and cpp_predfun are considered to be the same type 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);
[bearbeiten] Schlüsselwörter
[bearbeiten] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 4 | C++98 | Namen mit interner Bindung können Sprachbindungen haben | beschränkt auf Namen mit externer Bindung |
| CWG 341 | C++98 | Eine Funktion mit "C"-Sprachbindung kann denselben Namen wie eine globale Variable haben |
Das Programm ist in diesem Fall schlecht geformt. (keine Diagnose erforderlich, wenn sie in verschiedenen Übersetzungseinheiten vorkommen) |
| CWG 564 | C++98 | Das Programm war schlecht formuliert, wenn zwei Deklarationen sich nur in den Sprachbindungsspezifikationen unterscheiden (d. h. unterschiedliche String-Literale nach 'extern') |
Die tatsächlichen Sprachbindungen, die von den Deklarationen gegeben werden, werden stattdessen verglichen |
| CWG 2460 | C++20 | friend-Funktionen mit einer nachfolgenden requires Klausel und "C"-Sprachbindung hatten widersprüchliche Verhaltensweisen |
"C"-Sprachbindung wird in diesem Fall ignoriert |
| CWG 2483 | C++98 | Die Bindung der Typen von statischen Member-Funktionen die in "C"-Sprachblöcken erscheinen, war "C++" |
Die Bindung ist "C" |
[bearbeiten] 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 Linkage specifications [dcl.link]
- C++11 Standard (ISO/IEC 14882:2011)
- 7.5 Linkage specifications [dcl.link]
- C++03-Standard (ISO/IEC 14882:2003)
- 7.5 Linkage specifications [dcl.link]
- C++98 Standard (ISO/IEC 14882:1998)
- 7.5 Linkage specifications [dcl.link]