翻译单元和链接
在 C++ 程序中,符号(例如变量或函数名称)可以在其范围内进行任意次数的声明。 但是,一个符号只能被定义一次。 这就是“单一定义规则”(ODR)。 声明在程序中引入(或重新引入)一个名称,以及足够的信息,以便以后将该名称与定义联系起来。 定义引入一个名称,并提供创建它所需的全部信息。 如果名称表示变量,则定义会显式创建存储并进行初始化。 函数定义由签名和函数体组成。 类定义由类名和一个列出所有类成员的块组成。 (成员函数体可以选择在另一个文件中单独定义。)
下面的示例演示了一些声明:
int i;
int f(int x);
class C;
下面的示例演示了一些定义:
int i{42};
int f(int x){ return x * i; }
class C {
public:
void DoSomething();
};
一个程序包括一个或多个翻译单元。 一个翻译单元由一个实现文件及其直接或间接包含的所有标头组成。 实现文件通常具有文件扩展名 .cpp
或 .cxx
。 头文件通常具有扩展名 .h
或 .hpp
。 每个翻译单元由编译器独立编译。 编译完成后,链接器会将编译后的翻译单元合并到单个程序中。 ODR 规则的冲突通常显示为链接器错误。 在多个翻译单元中定义同一名称时,将发生链接器错误。
通常,使变量在多个文件中可见的最佳方式是在头文件中声明它。 然后,在需要声明的每个 .cpp
文件中添加一个 #include
指令。 通过在标头内容周围添加 include 防范,可以确保标头声明的名称对每个翻译单元只声明一次。 仅在一个实现文件中定义名称。
在 C++20 中,模块作为头文件的改进替代方法引入。
在某些情况下,可能需要在 .cpp
文件中声明全局变量或类。 在这些情况下,你需要一种方法来告知编译器和链接器名称所具有的链接类型。 链接的类型指定对象的名称是仅在一个文件中可见,还是在所有文件中可见。 链接的概念仅适用于全局名称。 链接的概念不适用于在一定范围内声明的名称。 范围是由一组封闭的大括号指定的,例如在函数或类的定义中。
外部链接与内部链接
Free 函数是在全局范围或命名空间范围内定义的函数。 默认情况下,非常量全局变量和 Free 函数具有外部链接;它们在程序中的任何翻译单元内可见。 其他任何全局对象都不能具有该名称。 具有内部链接或无链接的符号仅在声明它的翻译单元内可见。 当一个名称具有内部链接时,同一名称可能存在于另一个翻译单元中。 类定义或函数体中声明的变量没有链接。
如果要强制一个全局名称具有内部链接,可以将它显式声明为 static
。 此关键字将它的可见性限制在声明它的同一翻译单元内。 在此上下文中,static
表示与应用于局部变量时不同的内容。
默认情况下,以下对象具有内部链接:
const
对象constexpr
对象typedef
对象- 命名空间范围中的
static
对象
若要为 const
对象提供外部链接,请将其声明为 extern
并为其赋值:
extern const int value = 42;
有关详细信息,请参阅 extern
。
另请参阅
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈