C++ Translation Unit

C++ Translation Unit

本文关键字:Unit Translation C++      更新时间:2023-10-16

我真的不明白什么是翻译单元以及如何使用未命名的命名空间:

如果我有一个.cpp文件:

namespace
{
void extFunction()
{
std::cout << "Called Unnamed Namespace's function.n";
}
}

和一个主.cpp文件:

#include <iostream>
#include "ext.cpp"
using namespace std;
int main()
{
extFunction();

return 0;
}

为什么可以从另一个文件访问未命名命名空间的成员?

编辑:

感谢您的回复;但是,我如何使用未命名的命名空间,以及出于什么目的?

翻译单元基本上是你提供给编译器处理的代码块。编译器处理它并为链接器生成目标代码。链接器将来自所有翻译单元的目标代码组合在一起,以形成可执行文件。(有时您会看到与此不同的详细信息,例如,当您只有一个翻译单元时,看不到目标代码的文件。即使实现细节可能有所不同,该概念仍然有效。

因此,通常,编译时产生的.o(或.obj)文件和翻译单元之间存在一对一的对应关系。此外,通常,每个.cpp文件都会获得一个.o文件。因此,将每个.cpp文件视为其自己的翻译单元通常是合理的。直到你做一些非常规的事情。

使用#include指令时,会告诉编译器将该行替换为包含文件的全部内容。也就是说,提供给编译器的代码块包括原始文件和包含文件中的代码。如果将一个.cpp文件包含在另一个文件中,则提供给编译器的代码块将包含来自两个.cpp文件的代码,从而破坏.cpp文件和翻译单元之间的等效性。这通常被认为是一个坏主意。


让我们看一个例子。假设您有一个名为ext.cpp的文件,其中包含以下内容:

namespace
{
void extFunction()
{
std::cout << "Called Unnamed Namespace's function.n";
}
}

还假设您有一个名为main.cpp的文件,其中包含以下内容:

#include <iostream>
#include "ext.cpp"

int main()
{
extFunction();
return 0;
}

如果要编译main.cpp,编译器要做的第一件事就是预处理main.cpp。这将修改文件的内容,更改编译器看到的内容。预处理后,编译器将处理的代码块将如下所示。

[lots of code from the library header named "iostream"]
namespace
{
void extFunction()
{
std::cout << "Called Unnamed Namespace's function.n";
}
}

int main()
{
extFunction();
return 0;
}

此时,调用extFunction没有问题,因为编译器在其正在处理的代码块中看到未命名的命名空间。


有关使用未命名命名空间的请求信息的另一个示例。与上述相似,但不同。假设您有一个名为ext.cpp的文件,其中包含以下内容:

#include <iostream>
namespace
{
void extFunction()
{
std::cout << "Called Unnamed Namespace's function in EXT.n";
}
}
void extPublic()
{
extFunction();
}

我们还提供一个标头 (ext.h),它将声明具有外部链接的函数。

void extPublic();

现在转到main.cpp

#include <iostream>
#include "ext.h"  // <-- Including the header, not the source.
namespace
{
void extFunction()
{
std::cout << "Called Unnamed Namespace's function in MAIN.n";
}
}
int main()
{
extFunction();
extPublic();
return 0;
}

看啊!名为extFunction的函数有两个定义!链接器不会感到困惑吗?一点也不。这些功能在其翻译单元之外看不到,因此没有冲突。如果编译main.cpp、 编译ext.cpp并将main.oext.o链接到单个可执行文件中,则会得到以下输出。

在 MAIN 中调用未命名命名空间的函数。
在 EXT 中调用未命名命名空间的函数。

未命名命名空间的一个好处是,您不必担心与另一个源文件的未命名命名空间中的名称冲突。(当您的项目增长到包含数百个源文件时,这将成为一个更大的好处。