C++ C++;编译时,文件作用域对整个程序是全局的吗?

C++ C++;编译时,文件作用域对整个程序是全局的吗?,c++,scope,C++,Scope,据我所知(我可能是不正确的),当一个程序被编译时,所有的源文件都被合并成一个庞大的代码段。在这个阶段,整个程序能否“看到”每个其他文件范围的内容 下面是一个非常简单的例子: 1.cpp 2.cpp 假设1.cpp永远看不到Y,2.cpp永远看不到X,安全吗?也就是说,它们可以是任何东西,永远不会冲突或引起问题 据我所知(我可能是不正确的),当一个程序被编译时,所有的源文件都被合并成一个庞大的代码段 不是。编译是以翻译单位进行的。一次将编译一个.cpp文件。所有的#included头都会被复制到文

据我所知(我可能是不正确的),当一个程序被编译时,所有的源文件都被合并成一个庞大的代码段。在这个阶段,整个程序能否“看到”每个其他文件范围的内容

下面是一个非常简单的例子:

1.cpp

2.cpp

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

据我所知(我可能是不正确的),当一个程序被编译时,所有的源文件都被合并成一个庞大的代码段

不是。编译是以翻译单位进行的。一次将编译一个
.cpp
文件。所有的
#include
d头都会被复制到文件中,但结果会与程序中的其他
.cpp
分开编译。最后,它们都被连接在一起。这是所有符号和名称匹配的时候

如果您像那样在“文件范围”中声明变量,它们将对程序的其余部分可见(尽管您需要在另一个文件中声明才能实际使用它。这就是为什么声明通常放在头文件中)。如果希望转换单元作用域在外部不可见且不存在名称冲突的风险,请在未命名的命名空间中声明它们:

// File 1
namespace {
    int X = 0;
}


(请记住,在编译和链接方面,任何实际的实现都可能以自己的方式进行,但我认为我已经描述了一个合理的典型模型,您可以假装它对大多数简单的情况都是正确的。)

我认为它不会导致任何问题,除非您预先编译了这两个.cpp文件。只有预编译的头才是全局的(除非您不修改make文件)

在您的示例中,X和Y不会相互冲突,因为它们是不同的标识。这两个变量都在全局名称空间中定义,并具有外部链接。 当然,在1.cpp中声明Y之前,1.cpp不会看到Y

比如说

1.cpp

extern string Y;
int Y;
string Y;
static string Y;
namespace
{
    string Y;
}
这是变量Y的声明。它不是定义。因此,链接器将把这两个CPP中的Y和Y看作同一个对象。

但是,如果您将在1.cpp中定义Y,例如

1.cpp

extern string Y;
int Y;
string Y;
static string Y;
namespace
{
    string Y;
}
甚至

1.cpp

extern string Y;
int Y;
string Y;
static string Y;
namespace
{
    string Y;
}
然后,链接器将发出一个错误,因为它将找到具有外部链接的同名对象的两个定义。它也不知道该用什么定义

同时,您可以将1.cpp中的变量Y定义为具有内部链接。比如说

1.cpp

extern string Y;
int Y;
string Y;
static string Y;
namespace
{
    string Y;
}

1.cpp

extern string Y;
int Y;
string Y;
static string Y;
namespace
{
    string Y;
}

在这两种情况下,变量Y都有内部链接。在thjis情况下,Y的定义不会与2.cpp中Y的定义冲突,因为1.cpp中的变量Y不会出现在1.cpp之外。它不会被放置在具有外部链接的变量表中,链接器将不知道它。

首先,C++中没有文件范围。你呢 可能的意思是全局范围,这只是 命名空间范围

您还必须区分可见性和绑定: 首先确定在中的给定位置可以访问哪些符号 源代码;第二个确定符号的实体 绑定到。在给定的翻译单元中,您永远无法“看到” 未在该翻译单元中声明的符号,以 无论如何。在这个意义上,如果你有
intx在一个
源文件(
1.cpp
),并且不要在另一个源文件中声明
X
文件(
2.cpp
),包括在其他文件中包含的任何标题中 源文件,则
X
在另一个源文件中不可见。 另一方面,如果您不小心尝试定义另一个 在第二个源文件中名为
X
的实体,符号将 引用与第一个源文件中相同的实体;在 两个声明都定义一个变量的情况(如 例如),这是未定义的行为

因为这种未定义的行为很容易发生 无意中,您通常不希望定义变量 (或其他实体),除非您需要它们 在任何地方都可见(在这种情况下,您将 标题中的适当声明)。如果要定义 符号仅在单个翻译单元中可见,您将 将它放在未命名的名称空间中(实际上它有一个神奇的名称)

我已经发现了一个显著的证据,它们彼此可见,但是这个注释框太小,不能容纳它:-你的假设是错误的,至少在一般情况下是这样。@亮度在轨道上的种族:我仍然在学习C++,感谢您的澄清。cpp文件中的
static
关键字不也应该这样做吗?这是关于链接而不是可见性的。这两个都是重要因素。是的,但这种用法不赞成使用未命名的命名空间,即使在2003年的标准中也是如此:“[namespace.unnamed]2在命名空间范围内声明对象时,不赞成使用
static
关键字(见附录D);未命名的命名空间提供了更好的选择。”@BoBTFish
static
在某些情况下仍然有用。我经常使用它,例如,在与Python接口时;函数必须是
extern“C”
,这意味着名称空间(包括未命名的名称空间)将被忽略(实际上,无论如何),因此
static
是确保它们在其他翻译单元中不可见的唯一方法。@BoBTFish不,它已被弃用,但这种情况已经很久没有出现了。C++11没有预先做好准备,因为这是一件非常合理的事情。