C / C ++ Scope在两个不同的.cpp文件中

时间:2011-11-30 17:00:51

标签: c++ c

我想知道为什么你不能在2个不同的.cpp文件中声明一个同名的全局。我的理解是考虑范围,它应该只对特定的.cpp文件可见,而不是其他地方,但它显然是在抱怨。我这样做的原因是代码中的通用性,就是这样。任何想法?

编辑清晰度

a.cpp

int g_x;

b.cpp

int g_x;

6 个答案:

答案 0 :(得分:7)

使全局变量(或函数)仅对其声明的文件可见,

  1. 声明static
  2. (C ++中首选的方式)将变量放在无名空间中。看起来这会使它无法从命名空间外部访问,但它实际上做的是使对它所在的文件可见。
  3. 要访问在其他文件中声明的全局变量(不是static或在匿名命名空间中),请使用extern

    原因与两个不同文件中不能具有相同名称的功能的原因相同。它会混淆链接器,因为默认情况下全局变量具有外部链接。 static或在匿名命名空间中为它们提供内部链接,这使它们成为“本地全局变量”。

答案 1 :(得分:5)

问题:
全局变量具有 External linkage ,即:它们在整个程序中都可见 如果2个不同的文件具有相同符号名称的变量,则会中断ODR( One Definition Rule )。

一个定义规则(ODR),顾名思义,要求具有外部链接的对象,非内联函数,类,枚举或模板应具有一个定义在该计划中。


解决方案:
文件中的全局变量应具有内部链接,以避免违反ODR。 有两种方法可以实现这一目标:

将全局变量设置为文件static
使用匿名/未命名的命名空间


好读:
Anonymous/Unnamed namespace
Speaking Standardese: the One Definition Rule


对于Standerdese粉丝:
C ++ 11 3.2一个定义规则[basic.def.odr]

  

任何翻译单元都不得包含任何变量,函数,类类型,枚举类型或模板的多个定义。

第3段:

  

每个程序应该只包含该程序中使用的每个非内联函数或变量的一个定义;无需诊断。定义可以在程序中明确显示,可以在标准或用户定义的库中找到,或者(在适当的时候)隐式定义(见12.1,12.4和12.8)。内联函数应在每个使用它的翻译单元中定义。

C ++ 11 7.3.1.1未命名的命名空间[namespace.unnamed]

  

1 / unnamed-namespace-definition的行为就好像被

替换一样
inlineoptnamespace unique { /* empty body */ }    
using namespace unique ;      
namespace unique { namespace-body }       
  

其中inline出现,当且仅当它出现在unnamed-namespace-definition中时,翻译单元中所有出现的unique都被相同的标识符替换,并且此标识符与整个program中的所有其他标识符不同。 / p>

注意: C ++ 03不推荐使用static来声明命名空间范围内的对象,但在C ++ 11中删除了此弃用。

答案 2 :(得分:3)

您遇到链接器错误的原因是因为变量具有 extern链接,并且位于相同的命名空间(即全局变量)中。

通常和建议的补救措施是将它们放在不同的命名空间中。

您可以使用匿名命名空间来完成此操作,如下所示:

namespace {
    int my_global_variable;
}

此命名空间在每个翻译单元中都有一个唯一的名称。比如,在一个翻译单元中,自动名称可以是“gorblegorble123”。这就像一样编译器将以下代码放在它之后:

using namespace gorblegorble123;    // As if this is present.

与其他翻译单位同上,但名称不同。

这是最通用的技术。特别是它适用于类定义。


正如在其他一些答案中所提到的那样,可以或者使用static指定内部链接,该变量对链接器不可见。

对于C ++ 98和C ++ 03中命名空间范围内的对象,不推荐使用此用法,但在C ++ 11中删除了弃用。

static是一种有限的特殊情况符号,可以应用于对象和函数,但不能应用于类。

答案 3 :(得分:2)

声明变量static(C和C ++):

static int myGlobalVariable;

或在匿名命名空间中声明它(仅限C ++):

namespace {
    int myGlobalVariable;
}

答案 4 :(得分:1)

why you can not declare a global with the same name in 2 different .cpp files

因为任何具有单个实体的多个定义的程序都是格式错误的。在您的情况下,您有两个名为相同的实体,因此该程序格式不正确。

解决此问题的首选方法(至少在C ++ 03中)是使用未命名的命名空间:

file1.cpp

namespace
{
  int n;
};

file2.cpp

namespace
{
  int n;
};

在未命名的命名空间中放置声明会使该实体仅在该转换单元中可见。

答案 5 :(得分:1)

由于问题也标有'c',我想加5美分。在C中没有“一个定义规则”。

在C(C99及之前,不确定C1x)中,具有文件范围且没有存储类说明符的对象构成暂定定义。 (第6.9.2节)。

在第144页的后续示例1中,列出了几个示例,集中在一个文件中的定义/声明。 但是,extern声明与没有存储类说明符(i3)的声明一起很好地组合在一起,构成了一个外部链接的定义。

这意味着可能存在引用该定义的第二个文件,或者使用extern,或者没有存储类说明符。

所以在C中,你可能有两个文件都有暂定的定义,比如

int i3;

并且两者都将引用tupe int的一个变量,并且链接器将确保两者都引用相同的内存位置。 即使您在两个不同的文件中有int abc;char abc,常规链接器也不会产生错误;但希望它会警告你。

H& S5有关于各种类型的连接器将如何处理这种情况的更多细节,但使用通用存储器模型,上述情况得到了证实。至少恕我直言。

有关look here的进一步参考,尤其是Alok的答案。