C++_内部链接与外部链接
一.编译单元
一个程序包括一个或多个编译单元。
一个翻译单元由一个实现文件及其直接或间接包含的所有标头组成
每一个Cpp文件即为一个编译单元
单一定义规则”(ODR)
在 C++ 程序中,符号(例如变量或函数名称)可以在其范围内进行任意次数的声明。 但是,一个符号只能被定义一次
二.常见链接器错误
每个编译单元由编译器独立编译。编译完成后,链接器会将编译后的编译单元合并到单个程序中,
根据ODR 规则,在多个翻译单元中定义同一名称时,将发生链接器错误
常见 lnk2005 重复定义
三.如何使变量或函数在多个文件可见?
//引用 https://learn.microsoft.com/zh-cn/cpp/cpp/program-and-linkage-cpp?view=msvc-170
最佳方式是在头文件中声明它,需要声明的每个 .cpp 文件中添加一个 #include 指令,仅在一个实现文件中定义名称。
可能需要在 .cpp 文件中声明全局变量或类。 在这些情况下,你需要一种方法来告知编译器和链接器名称所具有的链接类型
注意: 链接的概念不适用于在一定范围内声明的名称。 范围是由一组封闭的大括号指定的,例如在函数或类的定义中。
四.外部链接与内部链接 (External vs. internal linkage)
Free:非成员函数 /非static函数
非常量全局变量和 Free 函数具有外部链接;它们在程序中的任何编译单元内可见
//类定义或函数体中声明的变量没有链接
即在一个编译单元中定义一个非const全局变量或一个非Static函数 ,在其他任何编译单元中都可见
五.内部链接类型: 仅对当前编译单元有效,其他编译单元为隐藏
具有内部链接类型
const对象
constexpr对象
typedef对象
命名空间范围中的 static 对象
//source1.h
//内置类型(例如 int)的声明将自动成为定义,因为编译器知道要为其分配多少空间。需要加extern 确定是一个声明
extern int a;
extern const int const_a;
void Test();
//source1.cpp
#include "Head_1.h"
#include <iostream>
using namespace std;
int a = 5;
extern const int const_a = 6;
static int static_a = 1;
void Test()
{
cout << "Test" << endl;
}
//main.cpp 中使用 a / const_a / void Test()
#include <iostream>
#include "Head_1.h"
using namespace std;
extern int a;
extern const int const_a;
extern void Test();
int main()
{
cout << a << endl;
cout << const_a << endl;
Test();
}
extern 关键字
//extern 表明变量或函数在另一个转换单元中定义
//必须在除定义变量的文件之外的所有文件中应用extern ,即在外部文件使用该变量 需要加extern
//const 变量由于具有内部链接性,为使具有外部链接性,定义时要其对转换 extern
//static 变量主要其隐藏作用,在文件之外不可见
如何 extern 定义一个const 类型,默认具有内部链接性,使其具有外部链接性?
* const 全局变量
* 定义 extern const int a = 5;
* 在某一个文件中 使用 extern const int a;
/* * 匿名命名空间 anonymous or unnamed namespaces 如非static函数 或非static全局变量/const 变量 ,仅在本文件中使用 ,使用匿名命名空间 //使用匿名命名空间 namespace { int MyFunc(){} } */
temp.h
extern int b;
temp.cpp
//
int b = 9;
main.cpp 中定义
//error lnk2005 int b重复定义
int b = 9;
//可使用匿名命名空间
namespace
{
int b = 5;
}