以下extern说明符的示例用法如何表现。
我们在文件one.c和two.c中都有一个全局变量int x 我们想在three.c中使用这些,所以在three.c中将此变量声明为
extern int x;
编译和链接这些文件会发生什么?
我的回答是:所有这些文件的编译都应该成功,但是由于x的多个声明,链接器应该在链接时标记错误。 C ++中的行为会有什么不同吗?
这些是从C和C ++中同时从两个文件引用int x(在three.c中)的任何方式。 在C ++中,我想我们可以使用命名空间来实现这一点。对?
答案 0 :(得分:6)
默认情况下,全局变量具有外部链接,这意味着它们可以被其他源文件(或“翻译单元”)使用。如果您使用static
关键字声明全局变量,它们将具有内部链接,这意味着它们将无法被其他源文件使用。
对于具有外部链接的变量,不能有多个具有相同名称的变量,否则链接器会抱怨。但是,只要至少有一个具有内部链接,您就可以拥有两个具有相同名称的变量,当然,您无法在同一源文件中引用它们。
extern
声明只是对编译器说“这里是某个变量的名称,在另一个翻译单元中定义了外部链接”,允许你引用该变量。
除了添加名称空间外,C ++完全相同。如果全局变量放在命名空间内,那么它们可以具有相同的名称而不会出现链接器错误,前提是它们位于不同的命名空间中。当然,对这些变量的所有引用都必须引用全名namespace::var_name
,或者使用using
声明来建立本地名称空间上下文。
C ++也有匿名命名空间,它完全等同于在C中使用static
关键字作为全局变量:在匿名命名空间内声明的所有变量和函数都有内部链接。
所以,回答你原来的问题,你是对的 - 编译会成功,但由于变量x
与外部链接的多重定义(特别是来自翻译单元{{1),链接会失败}和one.c
)。
从two.c
开始,无法同时引用两个变量three.c
。您需要在一个或两个模块中重命名x
,或者切换到C ++并在命名空间中放置至少一个x
。
答案 1 :(得分:1)
在C中,你可以这样做:
// one.c
static int x;
int *one_x = &x;
// two.c
static int x;
int *two_x = &x;
// three.c
extern int *one_x;
extern int *two_x;
现在,您可以从文件x
明确地引用文件one.c
中的x
或文件two.c
中的three.c
。
然而,这可能比它的价值更多。也许你应该为你的全局变量提出更具描述性的名称,而不是用理论方法来绕过C的单个全局命名空间。
答案 2 :(得分:0)
为了避免生成重复的符号,您应该在单个头文件(.h文件)中声明extern int x;
,然后让所有.c文件使用x #include
该头文件,并且在.c文件的一个中定义或初始化int x;
。
答案 3 :(得分:0)
您可能会对this question的答案感兴趣。
摘要:链接器可能会也可能不会链接该文件。这取决于变量的初始化。如果变量在不同文件中具有不同的初始化,它肯定会失败。
答案 4 :(得分:0)
请记住,你不能extern一个全局静态变量.. !!