言語リンケージ
異なるプログラミング言語で記述されたプログラム単位間のリンケージを提供します。
|
これは、宣言をモジュールから分離するためにも使用できます。 モジュールの所有権を参照してください。 |
(C++20以降) |
extern 文字列リテラル { 宣言シーケンス (オプション) } |
(1) | ||||||||
extern 文字列リテラル 宣言 |
(2) | ||||||||
| string-literal | - | 必要な言語リンケージを指定する評価されない文字列リテラル |
| 宣言シーケンス | - | ネストされたリンケージ仕様を含めることができる宣言のシーケンス |
| 宣言 | - | 宣言 |
目次 |
[編集] 説明
すべての関数型、外部リンケージを持つすべての関数名、および外部リンケージを持つすべての変数名には、 *言語リンケージ*と呼ばれるプロパティがあります。言語リンケージは、別のプログラミング言語で記述されたプログラム単位とリンクするために必要な要件のセット(呼び出し規約、名前マングリング(名前装飾)アルゴリズムなど)をカプセル化します。
サポートが保証されている言語リンケージは2つだけです。
- "C++"、デフォルトの言語リンケージ。
- "C"、これによりCプログラミング言語で記述された関数とリンクすることができ、C++プログラムでCで記述された単位から呼び出し可能な関数を定義できます。
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++ }
言語リンケージはすべての関数型の一部であるため、関数へのポインタも言語リンケージを維持します。関数型の言語リンケージ(呼び出し規約を表す)と関数名の言語リンケージ(名前マングリングを表す)は、互いに独立しています。
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 }
エンティティの2つの宣言が異なる言語リンケージを与える場合、プログラムは不正形式です。どちらの宣言も他方から到達可能でない場合、診断は必要ありません。リンケージ仕様のないエンティティの再宣言は、エンティティとその型(存在する場合)の言語リンケージを継承します。
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
[編集] "C"リンケージの特別ルール
クラスメンバ、末尾にrequires句を持つフレンド関数、(C++20以降)、または非静的メンバ関数が "C"言語ブロックに出現する場合、それらの型のリンケージは "C++"のままですが(ただし、パラメータ型があれば、それは "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 }
`C`を、"C"言語リンケージを持つ関数または変数を宣言する宣言とします。別の宣言 `D`が同じ名前のエンティティを宣言し、次のいずれかの条件を満たす場合、 `C`と `D`は同じエンティティを宣言します。
- `D`はグローバルスコープに属する変数を宣言します。
- `C`が変数を宣言する場合、 `D`も変数を宣言します。
- `C`が関数を宣言する場合、 `D`も関数を宣言します。
通常の再宣言とは異なり、 `C`と `D`は異なるターゲットスコープを持つことができます。
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” }
ただし、そのような宣言の制限は引き続き適用されます。つまり、両方とも関数を宣言するか、両方とも変数を宣言する必要があり、宣言されたエンティティは同じ型を持つ必要があります。
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 }
[編集] 注記
言語仕様は名前空間スコープにのみ配置できます。
言語仕様の波括弧はスコープを確立しません。
言語仕様がネストする場合、最も内側の仕様が有効な仕様です。
言語リンケージ仕様に直接含まれる宣言は、宣言された名前のリンケージを決定し、それが定義であるかどうかを判断するために、 extern指定子を含むかのように扱われます。
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"を使用すると、Cライブラリ関数の宣言を含むヘッダーファイルをC++プログラムに含めることができます。しかし、同じヘッダーファイルがCプログラムと共有される場合、 extern "C"(Cでは許可されていません)は、適切な #ifdef、通常は __cplusplusで隠す必要があります。
#ifdef __cplusplus extern "C" int foo(int, int); // C++ compiler sees this #else int foo(int, int); // C compiler sees this #endif
"C"と "C++"の言語リンケージで関数型を区別する最新のコンパイラは、Oracle Studioのみです。他のコンパイラは、C++標準で要求されるオーバーロードセット(std::qsort、 std::bsearch、 std::signal、 std::atexit、および 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*); // 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);
[編集] キーワード
[編集] 欠陥レポート
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 4 | C++98 | 内部リンケージを持つ名前は言語リンケージを持つことができる | 外部リンケージを持つ名前に限定される |
| CWG 341 | C++98 | "C"言語リンケージを持つ関数は グローバル変数と同じ名前を持つことができる |
この場合、プログラムは不適格である (それらが 異なる翻訳単位に出現する場合、診断は必要ありません) |
| CWG 564 | C++98 | プログラムは、2つの宣言が 言語リンケージ仕様のみが異なる場合、不正形式でした。 (つまり、 'extern'の後の文字列リテラルが異なる) |
実際の言語リンケージは 宣言によって比較されます。 |
| CWG 2460 | C++20 | 末尾に requires句を持つフレンド関数 と "C"言語リンケージは競合する動作をしていました。 |
"C"言語リンケージ この場合無視されます。 |
| CWG 2483 | C++98 | "C"言語ブロックに現れる静的メンバ関数の型のリンケージ は "C++"でした。 |
リンケージは "C"です。 |
[編集] 参考文献
- C++23標準 (ISO/IEC 14882:2024)
- 9.11 リンケージ仕様 [dcl.link]
- C++20 standard (ISO/IEC 14882:2020)
- 9.11 リンケージ仕様 [dcl.link]
- C++17 standard (ISO/IEC 14882:2017)
- 10.5 リンケージ仕様 [dcl.link]
- C++14 standard (ISO/IEC 14882:2014)
- 7.5 リンケージ仕様 [dcl.link]
- C++11 standard (ISO/IEC 14882:2011)
- 7.5 リンケージ仕様 [dcl.link]
- C++03 標準 (ISO/IEC 14882:2003)
- 7.5 リンケージ仕様 [dcl.link]
- C++98 標準 (ISO/IEC 14882:1998)
- 7.5 リンケージ仕様 [dcl.link]