如果一个变量在.h文件中被定义为"static",会发生什么?

3

Windows 8,Clang

hh.h文件:

#ifndef _H_
#define _H_
#include<string>
using std::string;
static string m; // If m is defined as static, the promble of multiple definitions will be solved.
#endif

foo.cpp

#include "hh.h"
int foo()
{
    m = "456";
}

bar.cpp

#include "hh.h"
int main()
{
m = "123";
}

使用-c选项编译foo.cpp和bar.cpp

然后,我使用“nm”命令检查导出符号表

00000000 b .bss
00000000 d .ctors
00000000 d .data
00000000 d .eh_frame
00000000 r .rdata
00000000 t .text
00000000 b m  // a local var, as 'b'
// others

否则,如果我没有使用static限定符来定义"string m",比如在hh.h文件中:
#ifndef _H_
#define _H_
#include<string>
using std::string;
string m;
#endif

而且,我使用“nm”命令来检查导出符号表。
00000000 b .bss
00000000 d .ctors
00000000 d .data
00000000 d .eh_frame
00000000 r .rdata
00000000 t .text
00000000 B m  // a global var, as 'B'
// others

链接器报告变量 m 有“重复定义”的问题。
我的想法是,在 hh.h 文件中,我编写了一条防御性语句来保护它不被多次包含(我使用 -E 选项检查了预编译文件)。那么,如果在最终的目标文件中,hh.h 不会被包含两次以上,为什么在头文件中声明的全局变量(如 m)可以被链接器重复访问?这是我的第一个问题。
另一方面,如果我将 m 声明为 static,这意味着只有包含了m声明的头文件的人才能使用m。但我希望变量 m 可以作为全局变量共享。这是我的第二个问题。
如果我的想法有任何误解,请指出,谢谢!

2
每个cpp文件中都会获得该变量的单独实例。 - user1143634
这并没有回答问题,但是以下划线开头且后面跟着一个大写字母(_H_)以及包含两个连续下划线的名称保留供实现使用。请勿在您的代码中使用它们。 - Pete Becker
1个回答

7
在头文件中将变量声明为static与在包含该头文件的每个文件中将其声明为static具有完全相同的效果。每个翻译单元(即.cpp文件)最终都会拥有自己的该变量实例,与其他翻译单元中的实例分开。这非常令人困惑,几乎肯定不是你想要的。请不要这样做。

2
正如OP所述,“但我希望变量m可以作为全局变量共享”。也许值得一提的是,在这种情况下,使用“extern”是更好的选择。 - Scheff's Cat
@duskwuff 你说得对。实际上,我想在多个文件中共享m,比如foo.cpp和bar.cpp。因为我不想在共享m的文件中写"extern string m"。所以,我想是否可以将它写入头文件中,这样就可以避免反复写extern关键字了。 - W.Cameron
@W.Cameron 看起来extern是解决你的问题的正确选择,但我在不提及静态初始化顺序灾难以及如何通过单例(例如Meyers Singleton)来解决它之前,不会推荐使用它。前者并不一定是任何全局变量的问题(取决于它的构造方式及其所依赖的其他因素),但后者在任何情况下都是一种有效的解决方案。 - Scheff's Cat

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