我非常有信心地认为,全局声明的变量在程序启动时分配(如果适用,则初始化)。
int globalgarbage;
unsigned int anumber = 42;
那么在函数内部定义的静态变量呢?
void doSomething()
{
static bool globalish = true;
// ...
}
globalish
的空间是什么时候分配的?我猜想应该是在程序开始时。但它是否也会在那时被初始化呢?还是只有在第一次调用doSomething()
时被初始化?
我对此很好奇,于是写了下面的测试程序,并使用g++ 4.1.2版本进行编译。
include <iostream>
#include <string>
using namespace std;
class test
{
public:
test(const char *name)
: _name(name)
{
cout << _name << " created" << endl;
}
~test()
{
cout << _name << " destroyed" << endl;
}
string _name;
};
test t("global variable");
void f()
{
static test t("static variable");
test t2("Local variable");
cout << "Function executed" << endl;
}
int main()
{
test t("local to main");
cout << "Program start" << endl;
f();
cout << "Program end" << endl;
return 0;
}
结果并不是我预期的那样。静态对象的构造函数直到第一次调用函数时才被调用。以下是输出:
global variable created
local to main created
Program start
static variable created
Local variable created
Function executed
Local variable destroyed
Program end
local to main destroyed
static variable destroyed
global variable destroyed
3.6.2 Initialization of non-local objects [basic.start.init]
1
The storage for objects with static storage duration (basic.stc.static) shall be zero-initialized (dcl.init) before any other initialization takes place. Objects of POD types (basic.types) with static storage duration initialized with constant expressions (expr.const) shall be initialized before any dynamic initialization takes place. Objects of namespace scope with static storage duration defined in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit. [Note: dcl.init.aggr describes the order in which aggregate members are initialized. The initialization of local static objects is described in stmt.dcl. ]
[more text below adding more liberties for compiler writers]
6.7 Declaration statement [stmt.dcl]
...
4
The zero-initialization (dcl.init) of all local objects with static storage duration (basic.stc.static) is performed before any other initialization takes place. A local object of POD type (basic.types) with static storage duration initialized with constant-expressions is initialized before its block is first entered. An implementation is permitted to perform early initialization of other local objects with static storage duration under the same conditions that an implementation is permitted to statically initialize an object with static storage duration in namespace scope (basic.start.init). Otherwise such an object is initialized the first time control passes through its declaration; such an object is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control re-enters the declaration (recursively) while the object is being initialized, the behavior is undefined. [Example:
int foo(int i) { static int s = foo(2*i); // recursive call - undefined return i+1; }
--end example]
5
The destructor for a local object with static storage duration will be executed if and only if the variable was constructed. [Note: basic.start.term describes the order in which local objects with static storage duration are destroyed. ]
所有静态变量的内存在程序加载时分配。但局部静态变量是在第一次使用时创建和初始化的,而不是在程序启动时。关于这个问题有一些很好的阅读资料,以及关于静态变量的一般性介绍,可以在这里找到。总的来说,我认为这些问题中的一些取决于具体的实现,尤其是如果你想知道这些东西在内存中的位置。
foo
中的静态变量,但编译器还会向函数 foo
添加一些额外的指令(机器码),以便在首次调用该函数时初始化静态变量(例如调用构造函数,如果适用)。#include <iostream>
#include <string>
using namespace std;
class test
{
public:
test(const char *name)
: _name(name)
{
cout << _name << " created" << endl;
}
~test()
{
cout << _name << " destroyed" << endl;
}
string _name;
static test t; // static member
};
test test::t("static in class");
test t("global variable");
void f()
{
static test t("static variable");
static int num = 10 ; // POD type, init before enter main function
test t2("Local variable");
cout << "Function executed" << endl;
}
int main()
{
test t("local to main");
cout << "Program start" << endl;
f();
cout << "Program end" << endl;
return 0;
}
结果:
static in class created
global variable created
local to main created
Program start
static variable created
Local variable created
Function executed
Local variable destroyed
Program end
local to main destroyed
static variable destroyed
global variable destroyed
static in class destroyed
num
在main
函数之前被初始化的结论的?请注意,如果初始化程序不仅仅是一个整数文字,那就不是这种情况:https://godbolt.org/z/Gasr7dTY8 很显然,在这个例子中,如果在main
函数之前初始化了num
,则预期的副作用将关闭。 - 463035818_is_not_a_number还是在第一次调用doSomething()时初始化?
是的,确实如此。这样做可以让你在适当的时候初始化全局访问的数据结构,例如在try/catch块内部。比如,不要这样写:
int foo = init(); // bad if init() throws something
int main() {
try {
...
}
catch(...){
...
}
}
您可以编写
int& foo() {
static int myfoo = init();
return myfoo;
}
在try/catch块内使用它。第一次调用时,变量将被初始化。然后,在第一次和下一次调用中,它的值将被返回(通过引用)。
int func(int x)
{
static int static_x = 4;
static_x = x;
printf ("Address = 0x%x",&static_x ); // prints 0x40a010
return static_x;
}
int main()
{
int x = 8;
uint32_t *ptr = (uint32_t *)(0x40a010); // static_x location
printf ("Initial = %d\n",*ptr);
func(x);
return 0;
}