我知道这个程序没有以适当的方式使用静态变量,但它显示了如何重现我所看到的行为:
Main.cpp:
int main(){
MyObject* p = new MyObject();
Header::i = 5;
printf("i %i\n", Header::i);
p->update();
return 0;
}
MyObject.cpp:
MyObject::MyObject(){
}
void MyObject::update(){
printf("i %i\n", Header::i);
}
Extern.h:
namespace Header {
static int i;
};
我得到的输出是:
i : 5
i : 0
为什么我不为两个输出获得5
?这个0
来自哪里?
你能解释静态变量是如何工作的吗?
答案 0 :(得分:51)
静态变量具有内部链接,这实际上意味着它们是编译单元的本地链接。由于您在2个源文件中包含的标头中声明了静态变量,因此您基本上有2个不同的变量:一个i
本地MyObject.cpp
和另一个i
,本地main.cpp
1}}
答案 1 :(得分:13)
每个翻译单元都有一个静态变量,其中包含标题,因为静态变量具有内部链接。
这个0来自哪里?
你没有在第二个翻译单元中初始化变量,静态变量是零初始化的,这就是0的来源。
在标准(§3.6.2/ 2)中:
具有静态存储持续时间(3.7.1)的变量应在进行任何其他初始化之前进行零初始化(8.5)。[...]
答案 2 :(得分:12)
你有两个变量我
static int i;
因为它有内部联系。这意味着包含相应头的每个编译单元都有自己的对象i,而其他编译单元对该编译单元中该对象的压力一无所知。
如果要删除说明符static
,则链接器应发出一条消息,表明该变量已定义两次。
如果在C ++ 2011中将变量放在未命名的命名空间中,可以实现相同的效果。例如,而不是
namespace Header {
static int i;
};
你可以写
namespace {
int i;
};
在这种情况下,我也有内部联系。这对C ++ 2011有效。
答案 3 :(得分:9)
您不应该在头文件中放置静态valiables。这导致包含该头的每个cpp文件在其编译单元中具有该静态本地的副本。
您可以做的是外部存储说明符:
部首:
namespace Header {
extern int i;
}
.cpp的:
namespace Header {
int i = 0;
}
答案 4 :(得分:7)
作为所有答案的补充。为什么会这样,已经解释过了。然而如何解决它,直到现在才建议只使用静态/外部方法。这有点像C一样。你不必使用C-linkage的项目的C部分中的标题,你可以使用C ++。
所以 IF 你真的要在你的代码中使用静态的东西。
将变量声明为类的成员:
<强> header.h 强>
MyGlobalVariableHoler
{
public: static int i;
};
<强>的main.cpp 强>
// class' statics have has to be initialized, otherwise linker error.
int MyGlobalVariableHoler::i=0;
<强> any_code.cpp 强>
#include <header.h>
MyGlobalVariableHolder::i=4711;
或者使用单例来避免显式初始化
<强> header.h 强>
MyGlobalVariableHolder
{
MyGlobalVariableHolder(){i=0;}
public:
static MyGlobalVariableHolder & instance()
{
static MyGlobalVariableHolder inst;
return inst;
}
int i;
};
<强> any_code.cpp 强>
#include <header.h>
MyGlobalVariableHolder::instance().i=4711;
答案 5 :(得分:5)
最好在头文件中使用extern
声明变量,以指定它具有外部链接。否则将发生上述行为或可能发生潜在的编译或链接问题。
static int i ; // i has internal linkage
extern int i ; // i has external linkage
答案 6 :(得分:4)
您对类级静态变量与命名空间级静态变量感到困惑。两者都通过X::y
资格访问,增加了混乱。其他人已经解释了实际原因(在汇编/联系层面)。
答案 7 :(得分:3)
声明为static的变量只在声明它的文件中具有作用域,因为可以使用extern声明从其他文件访问声明为static而不是static的变量。