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;
}

 

posted on 2022-11-18 00:32  Animer  阅读(167)  评论(0编辑  收藏  举报