当前位置: 首页 > 工具软件 > Linkage > 使用案例 >

C++ 的 Linkage

子车桐
2023-12-01

链接

在 C++ 代码运行之前,编译器和连接器的需要完成它们的工作。如果想要程序能够顺利地跑起来,我们需要了解 C++ 中的两个个至关重要的概念 translation unit (编译单元,简称 TU)one definition rule (定义一次规则,下面简称 ODR)

所谓的 TU 就是一个 source file (源文件) 和 它所引用的 header files (头文件) 。而 linkage (链接) 可以理解为一个变量或者一个函数是否只作用于某个 TU 。


内部链接

而链接又分为 internal linkage (内部连接)external linkage (外部链接) 。内部连接,顾名思义,如果一个变量是属于内部连接的话,那么它在每一个 TU 里面都是独一无二的。只要满足以下条件,对象的链接方式均为内部连接[^1]:

  • const object (如 const int*const double 等等)
  • constexpr objects (如 constexpr char*)
  • typedefs
  • static objects in namespace scope (如全局 static int age)

在 a.h 文件中声明并初始化 const int* iptr ,然后被包含到不同的 TU 中。我们不难发现每个独立的 TU 都有自己的一个 iptr ,它们互不干扰互不影响。

// a.h
const int* iptr = new int(111); 

//a.cpp
#include "a.h"
void scope_a()
{
    std::cout <<  *iptr << "\n";
}

// b.h 为空文件
// b.cpp
#include "b.h"
#include "a.h"
void scope_b()
{
    *iptr = 222;
    std::cout << *iptr << "\n";
}

// main.cpp
#include "a.h"
#include "b.h"
int main()
{
    *iptr = 333;
    std::cout <<  *iptr << "\n"; // 打印 333
    scope_a(); // 打印 111
    scope_b(); // 打印 222
}

外部链接

与内部链接不同的是,链接方式属于外部链接的变量,无论在多少个 TU 里,都是同一个对象。如果我们试图在 a.h 文件中声明并初始化一个变量 int num = 111 的话,程序会出错。因为这里的定义并不满足,上述内部链接的 4 个条件。

// a.h
int num = 111;
void scope_a();

//a.cpp
#include "a.h"
void scope_a()
{
    std::cout <<  num << "\n";
}

// b.cpp
#include "b.h"
#include "a.h"
void scope_b()
{
    std::cout << num << "\n";
}

// main.cpp
#include "a.h"
#include "b.h"
int main()
{
    std::cout << num << "\n";
    scope_a();
    scope_b();
}

很遗憾,上面的代码发生了连接错误:

"int num"  already defined in A.obj
"int num" already defined in A.obj
one or more multiply defined symbols found

num 的声明和定义是在 a.h 同时进行,所以出现这样的报错是正常的,因为违反了 ODR 。为了修正这样的错误,extern 关键字派上用场。值得注意的是,如果要使用 extern去修饰一个变量的话,该变量的声明和定义必须在源文件内进行。

// a.h
void scope_a();

//a.cpp
#include "a.h"
extern int num = -1;
void scope_a()
{
    std::cout <<  num << "\n";
}

// b.cpp
#include "b.h"
#include "a.h"
extern int num;
void scope_b()
{
	num = 0;
    std::cout << num << "\n";
}

// main.cpp
#include "a.h"
#include "b.h"
extern int num;
int main()
{
	num = 1;
    std::cout << num << "\n";
    scope_a();
    scope_b();
    std::cout << num << "\n";
}
输出结果:
1
1
0
0

总结

一般情况下,我们都会避免用全局变量。因为全局变量的使用不当,会给程序带来一定的风险。


Reference

^1 :https://docs.microsoft.com/en-us/cpp/cpp/program-and-linkage-cpp?view=vs-2019

 类似资料: