C/C++全局变量与静态全局变量的区别

76

可能是重复问题:
静态变量与全局变量

我对全局变量和静态全局变量之间的区别感到困惑。如果静态意味着此变量仅针对同一文件是全局的,那么为什么在两个不同的文件中相同的名称会导致名称冲突?

有人能解释一下吗?


3
如果两个变量在不同的文件中被声明为静态变量,那么它们不应该引起名称冲突。我刚刚进行了一个快速测试,结果符合预期。如果您发现这种情况并非如您所愿,请发布代码、期望值、实际值以及您使用的编译器。 - Kevin
2个回答

120

全局变量(非static)在创建.o文件时可供链接器在其他文件中使用。因此,如果您有两个类似于以下的文件,则会在a上发生名称冲突:

a.c:

#include <stdio.h>

int a;

int compute(void);

int main()
{
    a = 1;
    printf("%d %d\n", a, compute());
    return 0;
}

b.c:

int a;

int compute(void)
{
    a = 0;
    return a;
}

因为链接器无法确定使用哪个全局变量 a
然而,当你定义静态全局变量时,你告诉编译器只在该文件中保留该变量,并且不让链接器知道它的存在。因此,如果你在两个样例代码的 a 的定义中添加 static,你将不会遇到名称冲突的问题,因为链接器甚至不知道这两个文件中有一个名为 a 的变量:
a.c:
#include <stdio.h>

static int a;

int compute(void);

int main()
{
    a = 1;
    printf("%d %d\n", a, compute());
    return 0;
}

b.c:

static int a;

int compute(void)
{
    a = 0;
    return a;
}

这意味着每个文件都可以使用自己的a,而不知道其他文件中的变量。


另外,只要它们在不同的文件中,一个变量声明为static,另一个则未声明也是可以的。如果两个声明在同一个文件(翻译单元)中,其中一个声明为static,另一个声明为extern,请参阅此答案


声明一个为静态的,另一个不是静态的呢? - Kissaki
1
@kissaki,如果这些声明在不同的文件中,那么没关系。具有静态声明的文件将使用对其他文件不可见的静态变量。所有具有非静态变量声明的文件都将使用共享全局变量。 - Shahbaz
@skyline75489,我刚看了一下,你是对的。这似乎超出了C语言关于链接的最低要求。如果你有int a;,在Linux上使用gcc 5.2.1,我得到的变量被指定为“公共符号”(你可以使用nm查看此信息。nmC标记它)。int a = 0;被放置在BSS中(nmB标记它),而int a = something_else;被放置在“初始化数据”中(nmD标记它)。显然,GNU ld规则是,C中的符号与BD中的符号链接。我无法确定其他编译器和链接器是否显示此行为。 - Shahbaz
在上面的例子中,如果你初始化了两个a,你会得到链接错误。 - Shahbaz
1
“0, 0” 不是错误的。没有使用 “static”,两个 “a” 是链接在一起的,所以它们是同一个 “a”。在 “printf” 中,您正在打印 “a” 和 “compute()” 的结果,后者也修改了 “a”。C 语言规定函数参数的计算顺序是未指定的。这意味着编译器可以选择先计算 “a”,然后再计算 “compute()”,或者先计算 “compute()”,然后再计算 “a”。在第一种情况下,您将得到 “1, 0”,而在第二种情况下,您将得到 “0, 0”。两种情况都是有效的,实际上依赖于任何一种行为都是编程错误。 - Shahbaz
显示剩余6条评论

10

每个文件中静态的名称不应该导致名称冲突。如果你遇到了这种情况,请提供一个简短的演示代码,以及您正在使用的确切编译器,以便我们可以正确验证代码,假设它是正确的,妥善批评编译器。

只是顺带一提,C++ 中首选的方法是使用匿名命名空间:

namespace { 
    int not_a_static_variable;
}

说实话,虽然我不能指出很多客观优势...

1
说实话,虽然我不能指出很多客观的优势……也许这个主题可以在某种程度上有所帮助:为什么未命名的命名空间是静态变量的“更好”替代方案? - Nawaz
5
C++11取消了静态对象的弃用,所以现在两种方法都不特别“优先”。 - Mike Seymour
@MikeSeymour:这也是真的。 - Nawaz
@MikeSeymour:官方弃用的移除并不意味着它不被推荐使用。正如我试图暗示的那样,甚至有一些理由可以优先考虑它,只是不多(我在真实代码中遇到的唯一一个原因是想要将某些东西用作模板参数,至少就我个人而言,我只记得这种情况出现过一次或两次)。 - Jerry Coffin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接