如标题所示 - 程序如何知道,foo
在第二次调用函数时已经初始化:
int getFoo()
{
static int foo = 30;
return foo;
}
int main()
{
getFoo();
getFoo();
}
我想知道,程序是否存储了一些关于哪个静态变量已经初始化的附加信息。
编辑:
我在这里找到了答案:
为什么本地静态对象的初始化使用隐藏的保护标志?
就像我猜的那样——大多数编译器都存储了额外的“保护变量”。
如标题所示 - 程序如何知道,foo
在第二次调用函数时已经初始化:
int getFoo()
{
static int foo = 30;
return foo;
}
int main()
{
getFoo();
getFoo();
}
我想知道,程序是否存储了一些关于哪个静态变量已经初始化的附加信息。
编辑:
我在这里找到了答案:
为什么本地静态对象的初始化使用隐藏的保护标志?
就像我猜的那样——大多数编译器都存储了额外的“保护变量”。
看看[stmt.dcl]/4:
- 具有静态存储持续时间或线程存储持续时间的块范围变量的动态初始化在控制第一次通过其声明时执行;这样的变量在其初始化完成时被认为已初始化。如果初始化抛出异常退出,说明初始化未完成,下次控件进入声明时会再次尝试。如果控制在变量初始化时同时进入声明,则并发执行将等待初始化完成。94 如果控制在变量初始化时递归地重新进入声明,则行为未定义。
你必须在这里小心。Primitive static
s 在编译时初始化(只要初始化值是编译时常量,正如彼得指出的那样),因此在您的示例中,GetFoo
实际上只是返回一个常量。
然而...
static
初始化对象(或通过调用函数初始化原语)的 s 在第一次进入声明它们的范围时执行所述初始化。
此外,从 C++ 11 开始,这必须以线程安全的方式完成,这会产生大量额外的代码(尽管在第一次通过后没有太多的运行时开销),这可能是微控制器上的一个问题代码大小通常很重要。
这是一个具体的例子:
#include <iostream>
struct X
{
X () { std::cout << "Initialising m\n"; m = 7; }
int m;
};
void init_x ()
{
static X x;
}
int main () {
std::cout << "main called\n";
init_x ();
std::cout << "init_x returned\n";
}
输出:
main called
Initialising m
init_x returned