静态全局变量的奇怪行为
Strange behavior of static global variable
我知道这个程序没有以适当的方式使用静态变量,但它展示了如何重现我所看到的行为:
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
来自哪里?
你能解释一下静态变量是如何工作的吗?
静态变量具有内部链接,这实际上意味着它们对于编译单元而言是本地的。由于您在 2 个源文件中的 header 中声明了静态变量,因此您基本上有 2 个不同的变量:一个 i
局部于 MyObject.cpp
和另一个不同的 i
, main.cpp
本地
你有两个变量 i
static int i;
因为它有内部链接。这意味着包含相应 header 的每个编译单元都有自己的 object i 并且其他编译单元不知道该编译单元中 object 的存在。
如果您要删除说明符 static
,那么链接器应该发出一条消息,指出该变量被定义了两次。
如果在 C++ 2011 中将变量放在未命名的命名空间中,也可以达到相同的效果。例如,而不是
namespace Header {
static int i;
};
你可以写
namespace {
int i;
};
在这种情况下,变量 i 也有内部链接。这对 C++ 2011 有效。
声明为 static 的变量仅在声明它的文件中有范围,而声明为 static 的变量可以使用 extern 声明从其他文件访问。
您将 class 级静态变量与命名空间级静态变量混淆了。两者都通过 X::y
资格访问,增加了混乱。其他人已经解释了实际原因(在 compilation/linkage 级别)。
每个包含 header 的翻译单元都有一个静态变量,因为静态变量具有内部链接。
Where does this 0 come from ?
你没有初始化第二个翻译单元中的变量,静态变量是zero-initialized,这就是0的来源。
在标准 (§3.6.2/2) 中:
Variables with static storage duration (3.7.1) [...] shall be zero-initialized (8.5) before any other initialization takes place.[...]
最好在头文件中用 extern
声明变量,以指定它具有外部 linkage。否则会发生上述行为或潜在的编译或 link 问题。
static int i ; // i has internal linkage
extern int i ; // i has external linkage
您不应将静态变量放入 header 文件中。这导致每个包含 header 的 cpp 文件都将其静态本地副本复制到其编译单元。
你可以做的是外部存储说明符:
Header:
namespace Header {
extern int i;
}
Cpp:
namespace Header {
int i = 0;
}
作为对所有答案的补充。为什么会发生,已经解释过了。但是,到目前为止,仅建议使用 static/extern 方法来修复它。这个有点C-like。除非你不必使用 C-linkage 项目的 C-part 中的 header,否则你可以使用 C++。
所以 IF 你真的必须在你的代码中使用一些静态的东西。
要么将变量声明为class:
的成员
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;
我知道这个程序没有以适当的方式使用静态变量,但它展示了如何重现我所看到的行为:
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
来自哪里?
你能解释一下静态变量是如何工作的吗?
静态变量具有内部链接,这实际上意味着它们对于编译单元而言是本地的。由于您在 2 个源文件中的 header 中声明了静态变量,因此您基本上有 2 个不同的变量:一个 i
局部于 MyObject.cpp
和另一个不同的 i
, main.cpp
你有两个变量 i
static int i;
因为它有内部链接。这意味着包含相应 header 的每个编译单元都有自己的 object i 并且其他编译单元不知道该编译单元中 object 的存在。
如果您要删除说明符 static
,那么链接器应该发出一条消息,指出该变量被定义了两次。
如果在 C++ 2011 中将变量放在未命名的命名空间中,也可以达到相同的效果。例如,而不是
namespace Header {
static int i;
};
你可以写
namespace {
int i;
};
在这种情况下,变量 i 也有内部链接。这对 C++ 2011 有效。
声明为 static 的变量仅在声明它的文件中有范围,而声明为 static 的变量可以使用 extern 声明从其他文件访问。
您将 class 级静态变量与命名空间级静态变量混淆了。两者都通过 X::y
资格访问,增加了混乱。其他人已经解释了实际原因(在 compilation/linkage 级别)。
每个包含 header 的翻译单元都有一个静态变量,因为静态变量具有内部链接。
Where does this 0 come from ?
你没有初始化第二个翻译单元中的变量,静态变量是zero-initialized,这就是0的来源。
在标准 (§3.6.2/2) 中:
Variables with static storage duration (3.7.1) [...] shall be zero-initialized (8.5) before any other initialization takes place.[...]
最好在头文件中用 extern
声明变量,以指定它具有外部 linkage。否则会发生上述行为或潜在的编译或 link 问题。
static int i ; // i has internal linkage
extern int i ; // i has external linkage
您不应将静态变量放入 header 文件中。这导致每个包含 header 的 cpp 文件都将其静态本地副本复制到其编译单元。
你可以做的是外部存储说明符:
Header:
namespace Header {
extern int i;
}
Cpp:
namespace Header {
int i = 0;
}
作为对所有答案的补充。为什么会发生,已经解释过了。但是,到目前为止,仅建议使用 static/extern 方法来修复它。这个有点C-like。除非你不必使用 C-linkage 项目的 C-part 中的 header,否则你可以使用 C++。
所以 IF 你真的必须在你的代码中使用一些静态的东西。
要么将变量声明为class:
的成员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;