据我了解(我可能不正确),编译程序时,所有源文件都合并为一个大量的代码。在这个阶段,整个程序可以“看到”每个其他文件范围的内容吗?
这是一个非常简单的例子:
1.cpp
int X = 0;
2.cpp
string Y = "";
是否可以安全地假设1.cpp永远不会看到Y而2.cpp永远不会看到X?那就是它们可以是任何东西,从不冲突或引起问题?
答案 0 :(得分:4)
据我了解(我可能不正确),编译程序时,所有源文件都合并为一大堆代码。
没有。编译在翻译单元中进行。将一次编译.cpp
个文件。所有它的#include
d标题都将被逐字复制到文件中,但结果将与程序中的其他.cpp
分开编译。然后,他们最后一起链接。这是所有符号和名称匹配的时候。
如果你声明你的变量就是这样,在"文件范围",它们将对程序的其余部分可见(尽管你需要在另一个文件中声明)实际使用它。这就是声明通常会在头文件中的原因)。如果您想要翻译单元范围,在外部没有可见性且没有名称冲突的风险,请在未命名的命名空间中声明它们:
// File 1
namespace {
int X = 0;
}
和
// File 1
namespace {
float X = 0.0; // No clash!
}
(请记住,任何实际的实施都可以按照自己的方式进行编译和链接,但我认为我已经描述了一个相当典型的模型,你可以假装它是正确的思考最简单的情况。)
答案 1 :(得分:0)
除非你预先编译了这两个.cpp文件,否则我认为它不会导致任何问题。只有预编译的头文件是全局的(除非你不修改make文件)。
答案 2 :(得分:0)
在您的示例中,X和Y不会相互冲突,因为它们是不同的标识。这两个变量都在全局命名空间中定义,并具有外部链接。 当然1.cpp将不会看到Y,直到Y将在1.cpp中声明。
例如
<强> 1.cpp 强>
extern string Y;
这是变量Y的声明。它不是定义。因此,链接器会将2.cpp中的Y和Y视为同一个对象。
但是,如果您将1.cpp中的Y定义为
<强> 1.cpp 强>
int Y;
或甚至
<强> 1.cpp 强>
string Y;
然后链接器将发出错误,因为它将找到具有相同名称和外部链接的对象的两个定义。它不知道使用什么定义。
同时您可以将1.cpp中的变量Y定义为具有内部链接。例如
<强> 1.cpp 强>
static string Y;
或
<强> 1.cpp 强>
namespace
{
string Y;
}
在这两种情况下,变量Y都有内部联系。在这种情况下,Y的定义不会与2.cpp中Y的定义冲突,因为1.cpp中的变量Y不会出现在1.cpp之外。它不会放在具有外部链接的变量表中,链接器也不会对它有任何了解。
答案 3 :(得分:0)
首先,C ++中没有文件范围这样的东西。你是什么 可能意味着全球范围,这只是一个特例 名称范围。
你必须区分可见性和绑定:
首先确定您可以在给定位置访问哪些符号
源代码;第二个确定符号是什么实体
绑定到。在给定的翻译单元中,您永远不能看到&#34;
在该翻译单元中未声明的符号
某种方式。从这个意义上说,如果你有一个int X;
源文件(1.cpp
),并且不在其他来源中声明X
文件(2.cpp
),包括在另一个中包含的任何标头中
源文件,然后X
在其他源文件中不可见。
另一方面,如果你不小心尝试定义另一个
在第二个源文件中名为X
的实体,符号将
引用与第一个源文件中相同的实体;在里面
两个声明都定义一个变量的情况(如你的
例如),这是未定义的行为。
因为这样的未定义行为很容易发生 无意中,您通常不希望定义变量 (或其他实体)在全局命名空间中,除非您需要它们 随处可见(在这种情况下,你会把 标题中的适当声明)。如果你想要定义 只有在单个翻译单元中可见的符号,您才会 把它放在未命名的命名空间(实际上它有一个神奇的名字 这对每个翻译单位都是独一无二的。)