名前空間
変種
操作

言語リンケージ

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

異なるプログラミング言語で記述されたプログラム単位間のリンケージを提供します。

これは、宣言をモジュールから分離するためにも使用できます。 モジュールの所有権を参照してください。

(C++20以降)
extern 文字列リテラル { 宣言シーケンス (オプション) } (1)
extern 文字列リテラル 宣言 (2)
1) 言語仕様 文字列リテラルを、 宣言シーケンスで宣言されたすべての関数型、外部リンケージを持つ関数名、および外部リンケージを持つ変数に適用します。
2) 言語仕様 文字列リテラルを単一の宣言または定義に適用します。
string-literal - 必要な言語リンケージを指定する評価されない文字列リテラル
宣言シーケンス - ネストされたリンケージ仕様を含めることができる宣言のシーケンス
宣言 - 宣言

目次

[編集] 説明

すべての関数型、外部リンケージを持つすべての関数名、および外部リンケージを持つすべての変数名には、 *言語リンケージ*と呼ばれるプロパティがあります。言語リンケージは、別のプログラミング言語で記述されたプログラム単位とリンクするために必要な要件のセット(呼び出し規約名前マングリング(名前装飾)アルゴリズムなど)をカプセル化します。

サポートが保証されている言語リンケージは2つだけです。

  1. "C++"、デフォルトの言語リンケージ。
  2. "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::qsortstd::bsearchstd::signalstd::atexit、および std::at_quick_exit)を含む、言語リンケージのみが異なるオーバーロードを許可しません。 GCC bug 2316Clang bug 6277CWG 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);

[編集] キーワード

extern

[編集] 欠陥レポート

以下の動作変更を伴う欠陥報告が、以前に公開された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]
English 日本語 中文(简体) 中文(繁體)