extern (C++)

关键字 extern 可以应用于全局变量、函数或模板声明。 它指定符号具有 external 链接。 有关链接的背景信息以及为何不鼓励使用全局变量,请参阅翻译单元和链接

关键字 extern 具有四种含义,具体取决于上下文:

  • 在非 const 全局变量声明中,extern 指定变量或函数在另一个转换单元中定义。 必须在除定义变量的文件之外的所有文件中应用 extern

  • const 变量声明中,它指定变量具有 external 链接。 extern 必须应用于所有文件中的所有声明。 (默认情况下,全局 const 变量具有内部链接。)

  • extern "C" 指定函数在别处定义并使用 C 语言调用约定。 extern "C" 修饰符也可以应用于块中的多个函数声明。

  • 在模板声明中,extern 指定模板已在其他位置实例化。 extern 告知编译器它可以重复使用另一个实例化,而不是在当前位置创建新实例。 有关使用 extern 的详细信息,请参阅显式实例化

externconst 全局链接

链接器在全局变量声明之前看到 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)

extern 全局 const 链接

默认情况下,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 链接

在 Visual Studio 2017 版本 15.3 或更早版本中,编译器总是提供 constexpr 变量内部链接,即使在变量标记为 extern 时也是如此。 在 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++"。 所有标准包含文件都使用 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++ 链接是错误的。 此外,如果一个函数的两个声明出现在一个程序中,并且它们一个有链接规范,另一个没有,则有链接规范的声明必须是第一个。 将为已具有链接规范的函数的所有冗余声明提供第一个声明中指定的链接。 例如:

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- 编译器选项替代此检查。

另请参阅

关键字
翻译单元和链接
externC 中的存储类说明符
C 中的标识符行为
C 中的链接