C++中静态变量何时分配内存?

14

我是一个C++的新手,现在遇到了一个问题。

我在一本书中看到,当创建了一个类的对象后,静态变量就被分配了内存。那么,如果我将这个静态变量声明为全局的,它会在什么时候被初始化呢?

此外,我也在一些文章中读到过,静态变量被分配在堆上,它们不依赖于对象的构造...这是真的吗?如果是,请向我解释内存初始化的步骤,我需要帮助。

非常感谢!

3个回答

37

首先,请停止在C和C++中考虑全局变量,否则你将会持续处于困惑状态。该问题比如Python或Pascal等语言更加复杂,因此你不能仅使用一个单词来表示概念。

其次,“堆”和“栈”不存在 —— 它们属于操作系统和CPU的细节,与抽象的C++语言规范无关。

现在,变量有1)作用域,2)链接性和3)存储类别。使用static关键字可以影响这三个方面,具体取决于你在何处使用它。

作用域:变量声明的位置。如果在函数内部,则为函数作用域;如果在函数外部,则为文件作用域(你可能称之为“全局变量”)。

链接性:变量是否可以从其他编译单元中访问(当程序由多个源文件组成时相关)。

存储类别

静态变量在程序启动时以实现定义的方式分配,并在程序结束前存在。它们不能被“释放”或“重新分配”。(像其他人提到的BSS和DATA段一样,这是典型的实现方法)。

自动变量仅存在于函数作用域中,它们在函数进入时分配(可能初始化)(通常在CPU的栈上),并在函数退出时销毁。

动态存储类别是你可能称之为“堆”的东西。这些变量的存储直接通过malloc/free或new/delete进行操作。静态变量的存储方式与动态存储完全不同,并且这两种存储方式基本上是不兼容的。

例如:

===
// ALL file-scope variables have static storage class
int global1;        // file-scope, external linkage
static int global2; // file-scope, internal linkage

void f()
{
  static int x;     // static storage class, function-scope
  int y;            // automatic storage class, function-scope

  free(&x);         // ILLEGAL, WILL CRASH!
  free(&y);         // DITTO!
  free(&global1);   // DITTO!
}
===
现在,所有具有静态存储类(global1、global2和x)的变量都在程序启动之前分配并初始化。如果您没有指定初始值,则它们会以未指定的顺序进行默认初始化。(对于基本类型,这仅意味着填充零)。
静态变量仅在程序退出时释放。这意味着,在函数f中的“x”将仅被初始化一次(在程序启动时),并且它将保留在函数调用之间的值(与y相反,在每个函数入口分配并在每个函数退出时解除分配,因此也破坏其值)。请注意,在函数内使用静态变量与多线程和可重入性非常不兼容,除非您非常了解自己在做什么。

2
注意:它并不是完全未指定的。同一编译单元中的所有文件作用域变量按照声明/定义的顺序进行初始化。只是未指定跨编译单元的顺序(甚至未指定在初始化期间不同编译单元中的文件作用域变量是否交错)。 - Martin York
1
在上面的程序中:'global1'首先被初始化为0。'global2'第二次被初始化为0。'x'在第一次调用函数f()时被初始化。 - Martin York
我想在这里再提出一个疑问。静态函数和普通函数的初始化有什么区别?我读过,即使是普通函数,无论对象数量如何,也只有1个副本 - 这与静态函数非常相似... - Ishi
2
函数上的'static'只影响链接:函数获得内部链接,仅可从定义它的同一文件中访问。这使得可以在多个文件中定义名为'f'的静态函数。如果您尝试对非静态函数执行此操作,则链接器将抱怨符号'f'的多重定义。 - zvrba

11

标准是否规定全局变量的存储方式?如果是,我想要一个标准的参考。 - Martin York

1

在程序启动时(main函数之前),将为您的静态全局变量分配内存。

我对第二个问题毫无头绪。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接