extern (C++)

キーワード extern は、グローバル変数、関数、またはテンプレート宣言に適用できます。 これは、シンボルが external リンケージを持つことを示します。 リンケージの背景情報と、グローバル変数の使用が推奨される理由については、「翻訳単位とリンケージ」を参照してください。

キーワード extern には、コンテキストに応じて 4 つの意味があります。

  • constグローバル変数宣言では、extern によって変数または関数が別の翻訳単位で定義されることが指定されます。 変数が定義されているファイルを除くすべてのファイルで、extern を適用する必要があります。

  • 変数宣言 const では、変数に extern al リンケージがあることを指定します。 extern は、すべてのファイル内のすべての宣言に適用する必要があります。 (グローバル const 変数には既定で内部リンケージがあります)。

  • extern "C" は、関数が他の場所で定義され、C 言語呼び出し規則を使用することを指定します。 extern "C" 修飾子は、ブロック内の複数の関数宣言にも適用できます。

  • テンプレート宣言で、extern は、テンプレートが既に他の場所でインスタンス化済みである場合に指定します。 extern からコンパイラに、現在の場所に新しいインスタンスを作成するのではなく、他のインスタンス化を再利用できると指示されます。 この extern の使い方については、「明示的なインスタンス化」を参照してください。

const グローバルの extern リンケージ

リンカーは、グローバル変数宣言の前に extern が表示された場合、別の翻訳単位で定義を参照します。 既定では、グローバル スコープでの非 const 変数の宣言は、external です。 定義を提供しない宣言にのみ extern を適用します。

//fileA.cpp
int i = 42; // declaration and definition

//fileB.cpp
extern int i;  // declaration only. same as i in FileA

//fileC.cpp
extern int i;  // declaration only. same as i in FileA

//fileD.cpp
int i = 43; // LNK2005! 'i' already has a definition.
extern int i = 43; // same error (extern is ignored on definitions)

const グローバルの extern リンケージ

既定では、const グローバル変数には内部リンケージがあります。 変数に external リンケージを設定する場合は、extern キーワードを定義に適用し、他のファイル内の他のすべての宣言に適用します。

//fileA.cpp
extern const int i = 42; // extern const definition

//fileB.cpp
extern const int i;  // declaration only. same as i in FileA

extern constexpr リンケージ

2017 Visual Studio 15.3 以前では、変数が extern とマークされている場合でも、コンパイラは常に constexpr 変数内部リンケージを指定しました。 Visual Studio 2017 バージョン 15.5 以降、コンパイラ スイッチ (/Zc:externConstexpr) により、正しい標準準拠の動作が可能になります。 最終的にこの動作は既定値になります。 /permissive- オプションでは、/Zc:externConstexpr は有効になりません。

extern constexpr int x = 10; //error LNK2005: "int const x" already defined

ヘッダー ファイルには、宣言された変数 externconstexpr が含まれている場合、重複する宣言を正しく組み合わせるために、必ず __declspec(selectany) のマークを付ける必要があります。

extern constexpr __declspec(selectany) int x = 10;

extern "C"extern "C++" 関数宣言

C++ では、文字列を使用する場合、extern により、別の言語のリンケージ規則が宣言に使用されることが示されます。 C の関数とデータには、C リンケージを持つと以前に宣言されている場合にのみ、アクセスできます。 ただし、別にコンパイルされた翻訳単位で定義する必要があります。

Microsoft C++ は string-literal フィールドで文字列 "C""C++" をサポートします。 すべての標準の include ファイルは、extern "C" 構文を使用して、ランタイム ライブラリ関数が C++ プログラムで使用されるようにします。

次の例では、C リンケージを持つ名前を宣言する方法を示します。

// Declare printf with C linkage.
extern "C" int printf(const char *fmt, ...);

//  Cause everything in the specified
//  header files to have C linkage.
extern "C" {
    // add your #include statements here
#include <stdio.h>
}

//  Declare the two functions ShowChar
//  and GetChar with C linkage.
extern "C" {
    char ShowChar(char ch);
    char GetChar(void);
}

//  Define the two functions
//  ShowChar and GetChar with C linkage.
extern "C" char ShowChar(char ch) {
    putchar(ch);
    return ch;
}

extern "C" char GetChar(void) {
    char ch;
    ch = getchar();
    return ch;
}

// Declare a global variable, errno, with C linkage.
extern "C" int errno;

関数に複数のリンケージ指定がある場合は、一致する必要があります。 関数を C と C++ の両方のリンケージを持つとして宣言するとエラーになります。 また、プログラム内にリンケージ指定子を含むものと、含まない 2 つの関数宣言がある場合、リンケージ指定子を含む宣言を最初に記述する必要があります。 既にリンケージ指定を持つ関数の冗長な宣言には、最初の宣言で指定したリンケージが与えられます。 次に例を示します。

extern "C" int CFunc1();
...
int CFunc1();            // Redeclaration is benign; C linkage is
                         //  retained.

int CFunc2();
...
extern "C" int CFunc2(); // Error: not the first declaration of
                         //  CFunc2;  cannot contain linkage
                         //  specifier.

Visual Studio 2019 以降、/permissive- が指定されている場合、コンパイラによって extern "C" 関数パラメーターの宣言も一致することが確認されます。 extern "C" として宣言された関数をオーバーロードすることはできません。 Visual Studio 2019 バージョン 16.3 以降、/permissive- オプションの後に /Zc:externC- コンパイラ オプションを使用することで、このチェックをオーバーライドできます。

関連項目

キーワード
翻訳単位とリンケージ
extern ストレージ クラス指定子 (C)
C での識別子の動作
C でのリンケージ