名前空間
変種
操作

言語リンケージ

提供: cppreference.com
< cpp‎ | language
 
 
 
 

異なるプログラミング言語で書かれたモジュール間のリンク機構を提供します。

extern string-literal { declaration-seq(オプション) } (1)
extern string-literal declaration (2)
1) declaration-seq 内で宣言されたすべての関数型、外部リンケージを持つ関数名、および外部リンケージを持つ変数に、言語指定 string-literal を適用します。
2) 単一の宣言または定義に言語指定 string-literal を適用します。
string-literal - 要求される言語リンケージの名前。
declaration-seq - 宣言の並び。 ネストした言語指定を含んでも構いません。
declaration - 宣言。

目次

[編集] 説明

すべての関数型、外部リンケージを持つすべての関数名、外部リンケージを持つすべての変数名は、言語リンケージと呼ばれる性質を持ちます。 言語リンケージは別のプログラミング言語で書かれたモジュールとリンクするために必要な要件の集合 (呼び出し規約名前修飾のアルゴリズム、など) をカプセル化します。

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

1) "C++"。 デフォルトの言語リンケージ。
2) "C"。 C プログラミング言語で書かれた関数とリンクすること、および C で書かれたモジュールから呼べる関数を C++ プログラム内で定義することを可能とします。
extern "C" {
    int open(const char *pathname, int flags); // C の関数の宣言。
}
 
int main()
{
    int fd = open("test.txt", 0); // C++ のプログラムから C の関数を呼びます。
}
 
// この C++ の関数は C のコードから呼べます。
extern "C" void handler(int) {
    std::cout << "Callback invoked\n"; // C++ を使用できます。
}

言語リンケージはすべての関数型の一部です。 関数ポインタも同様に言語リンケージを保持します。 関数型の言語リンケージ (呼び出し規約を表します) および関数名の言語リンケージ (名前修飾を表します) はお互いに独立しています。

extern "C" void f1(void(*pf)()); // 引数を取らず void を返す C の関数
                                 // へのポインタを取って void を返す
                                 // C リンケージの関数 f1 を宣言します。
extern "C" typedef void FUNC(); // 引数を取らず void を返す C の関数型
                                // として FUNC を宣言します。
FUNC f2;            // 名前 f2 は C++ リンケージを持ちますが、その型は C の関数です。
extern "C" FUNC f3; // 名前 f3 は C リンケージを持ち、その型は C の関数 void() です。
void (*pf2)(FUNC*); // 名前 pf2 は C++ リンケージを持ち、その型は
                    // 「『引数を取らず void を返す C の関数へのポインタ』型の引数
                    // を1個取り void を返す C++ の関数へのポインタ」です。
extern "C" {
    static void f4(); // 関数 f4 の名前は内部リンケージ (言語なし) を持ちますが、
                      // その関数の型は C 言語リンケージを持ちます。
}

同じ名前空間で同じ名前かつ同じ引数リストを持つ2つの関数が2つの異なる言語リンケージを持つことはできません (しかし、std::qsortstd::bsearch の場合のように、引数のリンケージはそのようなオーバーロードを許しても良いことに注意してください)。 同様に、同じ名前空間で2つの変数が2つの異なる言語リンケージを持つことはできません。

[編集] 「C」リンケージに対する特別なルール

1) "C" 言語ブロック内にクラスメンバの宣言およびメンバ関数型の宣言が現れたとき、それらのリンケージは "C++" のままになります。
2) 異なる名前空間で同じ非修飾名を持つ2つの関数が宣言され、両方とも "C" 言語リンケージを持つとき、それらの宣言は同じ関数を参照します。
3) 異なる名前空間に同じ名前を持つ "C" 言語リンケージの2つの変数が現れたとき、それらは同じ変数を参照します。
4) 同じ名前空間で定義されたか異なる名前空間で定義されたかにかかわらず、 "C" の変数と "C" の関数が同じ名前を持つことはできません。

[編集] ノート

言語指定は名前空間スコープにのみ現れることができます。

言語指定の波括弧はスコープを確立しません。

言語指定がネストしたときは、最も内側の指定が有効になります。

関数は、言語指定付きで宣言された後、言語指定なしで再宣言でき、2回目の宣言では1回目の言語指定が再使用されます。 逆は真ではありません。 最初の宣言が言語リンケージを持たない場合、それは "C++" とみなされ、別の言語での再宣言はエラーになります。

言語リンケージ指定内に直接含まれる宣言は、宣言される名前のリンケージおよびそれが定義かどうかを決定する目的に対して、 extern 指定子を持っているかのように扱われます。

extern "C" int x; // 宣言ですが定義ではありません。
// 上の行は extern "C" { extern int x; } と同等です。
 
extern "C" { int x; } // 宣言かつ定義です。

extern "C" は C のライブラリ関数の宣言を含むヘッダファイルを C++ プログラムでインクルードすることを可能としますが、同じヘッダファイルを C のプログラムと共有する場合、 extern "C" (C では使用できません) は適切な #ifdef (一般的には __cplusplus) で隠蔽しなければなりません。

#ifdef __cplusplus
extern "C" int foo(int, int); // C++ コンパイラはこちらを見ます。
#else
int foo(int, int);            // C コンパイラはこちらを見ます。
#endif

[編集] 参考文献

  • 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]