C ++文件范围是否在编译时成为整个程序的全局?

时间:2014-05-14 08:58:39

标签: c++ scope

据我了解(我可能不正确),编译程序时,所有源文件都合并为一个大量的代码。在这个阶段,整个程序可以“看到”每个其他文件范围的内容吗?

这是一个非常简单的例子:

1.cpp

int X = 0;

2.cpp

string Y = "";

是否可以安全地假设1.cpp永远不会看到Y而2.cpp永远不会看到X?那就是它们可以是任何东西,从不冲突或引起问题?

4 个答案:

答案 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的实体,符号将 引用与第一个源文件中相同的实体;在里面 两个声明都定义一个变量的情况(如你的 例如),这是未定义的行为。

因为这样的未定义行为很容易发生 无意中,您通常不希望定义变量 (或其他实体)在全局命名空间中,除非您需要它们 随处可见(在这种情况下,你会把 标题中的适当声明)。如果你想要定义 只有在单个翻译单元中可见的符号,您才会 把它放在未命名的命名空间(实际上它有一个神奇的名字 这对每个翻译单位都是独一无二的。)