首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >编译器是如何实现静态变量初始化的?

编译器是如何实现静态变量初始化的?
EN

Stack Overflow用户
提问于 2009-05-22 15:20:50
回答 3查看 21.5K关注 0票数 22

我对函数中静态变量的底层实现很好奇。

如果我声明一个基本类型的静态变量(char、int、double等),并给它一个初始值,我想编译器只是在调用main()之前在程序的最开始设置该变量的值:

代码语言:javascript
复制
void SomeFunction();

int main(int argCount, char ** argList)
{
    // at this point, the memory reserved for 'answer'
    // already contains the value of 42
    SomeFunction();
}

void SomeFunction()
{
    static int answer = 42;
}

但是,如果静态变量是类的实例:

代码语言:javascript
复制
class MyClass
{
    //...
};

void SomeFunction();

int main(int argCount, char ** argList)
{
    SomeFunction();
}

void SomeFunction()
{
    static MyClass myVar;
}

我知道在第一次调用函数之前,它不会被初始化。由于编译器无法知道函数何时会被首次调用,它是如何产生这种行为的呢?它本质上是不是在函数体中引入了一个if块?

代码语言:javascript
复制
static bool initialized = 0;
if (!initialized)
{
    // construct myVar
    initialized = 1;
}
EN

回答 3

Stack Overflow用户

发布于 2009-05-22 15:51:35

This question涵盖了类似的内容,但没有提到线程安全。无论如何,C++0x将使函数静态初始化线程安全。

(请参阅关于函数静态的C++0x FCD,6.7/4:“如果在初始化变量时控制并发地进入声明,则并发执行应等待初始化完成。”)

另一件没有提到的事情是,函数静态函数是以与其构造相反的顺序被析构的,因此编译器维护了一个析构函数列表,以便在关闭时调用(这可能与atexit使用的列表相同,也可能不同)。

票数 11
EN

Stack Overflow用户

发布于 2009-05-22 15:32:26

您所说的一切都是对的,包括作为公共实现的initialized标志。这就是为什么静态局部变量的初始化不是线程安全的,以及pthread_once存在的原因。

一个小小的警告:编译器必须发出“行为就像”静态局部变量在第一次使用时被构造的代码。由于整数初始化没有副作用(并且不调用用户代码),因此在初始化int时由编译器决定。用户代码不能“合法”地找出它做了什么。

显然,您可以查看汇编代码,或者引发未定义的行为,并从实际发生的情况中进行推断。但是,C++标准并没有将此作为声称行为不是“好像”它做了规范所说的那样的有效理由。

票数 2
EN

Stack Overflow用户

发布于 2009-05-22 16:27:57

另一个转折是在嵌入式代码中,在main()之前运行的代码(cinit/随便什么)可以将预先初始化的数据(静态和非静态)从可能驻留在ROM中的常量数据段复制到ram中。当代码可能不是从某种后备存储(磁盘)运行时,这是很有用的,可以从这些后备存储(磁盘)重新加载代码。同样,这并不违反语言的要求,因为这是在main()之前完成的。

稍微有点离题:虽然我还没见过太多的工作(除了Emacs之外),但程序或编译器基本上可以在进程中运行代码,实例化/初始化对象,然后冻结和转储进程。Emacs执行与此类似的操作,加载大量的elisp (即,咬住它),然后将运行状态转储为工作的可执行文件,以避免每次调用时的解析开销。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/898432

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档