静态全局变量的奇怪行为

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

  • 不要使用`static`.在标题中使用`extern`,在单个源文件中初始化.但是应该像瘟疫那样避免全球变量. (18认同)

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有效.


Ale*_*bin 9

您不应该在头文件中放置静态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)


Val*_*itz 7

作为所有答案的补充.为什么会这样,已经解释过了.然而如何解决它,直到现在才建议只使用静态/外部方法.这有点像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)


Ide*_*ty1 5

最好extern在头文件中声明变量,以指定它具有外部链接.否则将发生上述行为或可能发生潜在的编译或链接问题.

static int i ; // i has internal linkage
extern int i ; // i has external linkage
Run Code Online (Sandbox Code Playgroud)