我真的不明白什么是翻译单元以及如何使用未命名的命名空间:
如果我有一个 .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();
}
我们还提供一个 header (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.o
和ext.o
链接成单个可执行文件,您将获得以下输出。
Called Unnamed Namespace's function in MAIN.
Called Unnamed Namespace's function in EXT.
未命名命名空间的一个好处是您不必担心与另一个源文件的未命名命名空间中的名称发生冲突。 (当您的项目增长到包含数百个源文件时,这会带来更大的好处。)
关于C++ 翻译单元,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55441843/