extern "C"
C言語リンケージを持つことを宣言します。これは外部連携や内部連携とは異なります。デフォルトでは、C++ プログラム内のすべてに C++ 言語リンケージがありますが、指定することでこれを繰り返すことができますextern "C++"
。
外部リンケージとは、適切なヘッダーを含めるか、適切な宣言を提供することを前提として、個別にコンパイルされた他のソース ファイルに名前が表示されることを意味します。これにより、 で関数を定義foo
しa.cpp
、 から呼び出すことができますb.cpp
。C++ プログラムのネームスペース スコープのほとんどの名前には、外部リンケージがあります。例外は、内部リンケージを持つものとリンケージを持たないものです。を指定することで、何かを外部リンケージを持つものとして明示的にマークできますextern
。これは とは異なりextern "C"
ます。
内部リンケージは、名前が現在のコンパイル単位に固有であることを意味し、別のソース ファイルから変数または関数にアクセスすることはできません。宣言されたファイル スコープ変数と関数にはstatic
、内部リンケージがあります。また、const
定数式で初期化された名前空間スコープの整数変数には、デフォルトで内部リンケージがありますが、明示的にオーバーライドできますextern
。
最後に、ローカル変数とクラスにはリンケージがありません。名前は、宣言されている関数に対してローカルであり、その関数の外部からアクセスすることはできません。extern
名前空間スコープで変数に本当にアクセスしたいことを示すために使用できます。
テンプレートはローカル スコープで定義することはできませんが、内部リンクまたは外部リンクのいずれかを持つことができます。
int i; // namespace scope variable has external linkage
extern int j; // explicitly mark j with external linkage
static int k; // k has internal linkage
int const n=42; // internal linkage
extern int const m=99; // external linkage
void foo(); // foo has external linkage; it may be defined in this source file or another
extern void foo(); // explicitly mark foo with external linkage
static void bar(); // bar has internal linkage, and must be defined in this source file
void foo(){} // definition of foo, visible from other source files
void bar(){} // definition of bar, not visible from other source files (internal linkage)
static void baz(){} // declare and define baz with internal linkage
template<typename T> void foobar(){} // foobar has external linkage
template<typename T>
static void foobaz(){} // foobaz has internal linkage
void wibble()
{
int i; // local, no linkage
extern int i; // references i, declared above with external linkage
}
extern "C"
{
int i2; // namespace scope variable has external linkage, and "C" linkage
extern int j2; // explicitly mark j2 with external linkage and "C" linkage
static int k2; // k2 has internal linkage and "C" linkage
int const n2=42; // internal linkage and "C" linkage
extern int const m2=99; // external linkage and "C" linkage
void foo2(); // foo2 has external linkage and "C" linkage
static void bar2(); // bar2 has internal linkage and "C" linkage
void foo2(){} // definition of foo2, still with external linkage and "C" linkage
void bar2(){} // definition of bar2, still with internal linkage and "C" linkage
static void baz(){} // declare and define baz with internal linkage
}
エラー メッセージは正しいです --- テンプレートはextern "C"
リンケージを持つことができません。
基本レベルでは、テンプレートはextern "C"
C と互換性がないため、リンケージを持つことはできません。特に、テンプレートは単一のクラスまたは関数を定義するだけでなく、同じ名前を共有するクラスまたは関数のファミリーを定義しますが、それらのテンプレート パラメータ。
指定された名前を持つ関数は 1 つだけ宣言できますextern "C"
。名前マングリングについて考えると、これは理にかなっています。C では、関数foo
は通常、foo
または_foo
シンボル テーブルで呼び出されます。C++ では、 のオーバーロードが多数ある可能性があるfoo
ため、シグネチャはシンボル テーブルの「マングルされた」名前に組み込まれ、区別するために または または 他の何かを取得する場合が$3fooV
ありfoo$void
ます。C++ では、指定されたプラットフォームの C スキームに従ってマークされた単一のオーバーロードがマングルされますが、他のオーバーロードは通常のマングルされた名前を保持します。foo(void)
foo(int)
extern "C"
テンプレートを宣言するにextern "C"
は、すべてのインスタンス化を にする必要がありますextern "C"
。これは、「指定された名前を持つ関数は 1 つだけにすることができるextern "C"
」という規則に矛盾します。
struct
C にはs の名前マングリングはありませんがstruct
、指定された名前を持つものは 1 つだけです。したがって、クラス テンプレートの禁止extern "C"
も理にかなっています --- テンプレートは同じ名前のクラスのファミリを定義するため、どのクラスが C に対応しstruct
ますか?