静态全局变量的奇怪行为

时间:2015-06-25 09:00:17

标签: c++ static global

我知道这个程序没有以适当的方式使用静态变量,但它显示了如何重现我所看到的行为:

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来自哪里? 你能解释静态变量是如何工作的吗?

8 个答案:

答案 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的变量。