定义:声明外部变量(在函数或者文件外部定义的全局变量)
一般而言,C++ 全局变量的作用范围仅限于当前的文件,但同时 C++ 也支持分离式编译,允许将程序分割为若干个文件被独立编译。
于是就需要在文件间共享变量数据,这里 extern 就发挥了作用。
extern 用于指示变量或函数的定义在另一个源文件中,并在当前源文件中声明。说明该符号具有外部链接(external linkage)属性。也就是告诉编译器,这个符号在别处定义了,你先编译,到时候链接器会去别的地方找这个符号定义的地址。
首先明白 C/C++ 中变量的声明和定义是两个不同的概念。声明是指告诉编译器某个符号的存在,在程序变量表中记录类型和名字,而定义则是指为该符号分配内存空间或实现其代码逻辑。
凡是没有带 extern 的声明同时也都是定义。而对函数而言,带有 {} 是定义,否则是声明。如果想声明一个变量而非定义它,就在变量名前添加关键字 extern, 且不要显示的初始化变量。
// 声明
extern int zzj;
int fun(int n);
//定义
int zj = 100;
int fun(int n) {return n;}
在 C++ 中,链接属性是指程序在编译、链接和执行阶段如何处理符号的可见性和重复定义。C++ 语言规定有以下链接属性:
1. 外部链接(External Linkage)
外部链接的符号可以在不同的源文件之间共享,并且在整个程序执行期间可见。全局变量和函数都具有外部链接。
2. 内部链接(Internal Linkage)
内部链接的符号只能在当前源文件内部使用,不能被其他源文件访问。用 static 修饰的全局变量和函数具有内部链接。
3. 无连接 (No Linkage)
无链接的符号只能在当前代码块内部使用,不能被其他函数或代码块访问。用 const 或 constexpr 修饰的常量具有无链接属性(通常编译器是不会为 const 对象分配内存,也就无法链接)。
4. 外部 C 链接(External C Linkage)
外部 C 链接的符号与外部链接类似,可以在不同的源文件之间共享,并且在整个程序执行期间可见。
在 C++ 中,可以用 extern "C" 关键字来指定外部 C 链接,从而使用一些 C 的静态库。
声明变量或函数的存在,但不进行定义,让编译器在链接时在其他源文件中查找定义。
当链接器在一个全局变量声明前看到 extern 关键字,他会尝试在其他文件中寻找这个变量的定义。这里强调全局且非常量的原因是:全局非常量默认是外部链接的。
//a.CPP
int a = 100;
//b,cpp
extern int a;
//c.cpp
extern int a; //错误:多重定义
全局常量默认是内部链接的,所以想要在文件间传递全局常量则需要在定义时指明 extern。
// a.cpp
extern const int a = 100;
const int b = 200;
// b,cpp
extern const int a;
extern const int b; // 会报链接错误
在编译期,extern 用于告诉编译器某个变量或函数的定义在其他源文件,编译器会为生成一个符号表项,并在当前源文件中建立一个对该符号的引用。这个引用时一个未定义的符号,编译器在后续的链接过程中会在其他源文件中查找这个符号的定义。
在链接期,链接器将多个目标文件合并成一个可执行文件,并且在当前源文件中声明的符号,会在其它源文件中找到对应的定义,并将它们链接起来。
extern "C" 是 C++ 语言提供的一种机制,用于在 C++ 代码中调用 C 语言编写的函数和变量。
如果不同 extern C, 由于 C++ 和 C 语言在编译和链接时使用的命名规则不同,这会导致 C++ 代码无法调用 C 语言编写的函数或变量。
函数的命名规则
对于 C++ 语言,由于需要支持重载,所以一个函数的链接名是由函数的名称、参数类型和返回值类型等信息组成的,用于在编译和链接时唯一标识该函数。
函数的链接名的生成规则在不同编译器和操作系统上可能有所不同,一般是由编译器自动处理,不需要手动指定。
而 C 语言的链接函数名规则和 C++ 不一样,通过在 C++ 中使用 extern "C" 关键字,可以将 C 编译器的命名规则转换为 C++ 语言的命名规则,从而使得 C++ 代码可以调用 C 语言的函数或变量
extern "C" 的语法格式如下:
exern "C"{
// C 语言函数或变量的声明
}
使用 extern "C" 声明的函数或变量会采用 C 语言的链接规则,即符号的名称和调用约定与 C 语言相同。