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