C++中静态变量的存储位置是何时确定的?

4

我有如下简单程序:

int main()
{
    int x = 5;
    static int y = x;
    return (0);
}

使用gcc编译时,static int y = x; 这一行会产生错误,错误信息为 "initializer element is not constant"。我猜测这是由于 y 是一个静态变量,在编译时需要知道它在存储空间(data/bss)中的位置以及初始值。

然而,当使用g++编译时,没有任何错误,并且程序正常运行(打印出5)。

我的问题如下:

  1. 我的猜测正确吗?
  2. 如果是的话,在C++中为什么能够对静态变量进行这样的初始化?

对我来说工作得很好:https://godbolt.org/z/qc3f9r - The Philomath
@ThePhilomath 这就是问题所在,它在C++中可以工作,但在C中不行。 - Yksisarvinen
@Yksisarvinen:OP提到了“gcc”。我正在使用“gcc”。我错过了什么吗? - The Philomath
是的,你关于静态初始化的说法是正确的。它发生在编译时。静态变量在编译时被初始化,并在运行时放置在代码的可执行部分中。 - Giriteja Bille
1
@ThePhilomath OP提到了gccg++。不幸的是,“GCC”是两者的通用名称,但是gcc命令默认构建C,而g++则构建C ++。这种差异还有更多,但我从未深入研究过,因此无法很好地解释它。 - Yksisarvinen
3个回答

7

您的程序在C++中很好地形成,因为具有静态存储期的局部变量不是在启动时初始化(对于常量表达式有一些例外;在此示例中不适用),而是在第一次控制通过其声明时进行初始化,此时初始化表达式包含局部非静态变量 x 已经可用。

引用 cppreference / Storage duration - Static local variables [重点 是我的]

使用 static 或 thread_local (自 C++11 起) 说明符声明的块范围变量具有静态或线程 (自 C++11 起) 存储期,但是它们在第一次控制通过其声明时进行初始化(除非它们的初始化是零或常量初始化,在进入块之前可以执行)。在所有后续调用中,声明将被跳过。

然而,在C语言中,静态初始化不遵循相同的规则; 来自 cppreference / C language - Initialization:

当初始化一个具有静态或线程局部存储期的对象时,初始值中的每个表达式都必须是常量表达式或字符串字面值。因此,在 C 中,您的程序是不合法的。

谢谢!如果是这样,那么 y 存储在哪里?我猜是 BSS 区? - localhost
1
@Ben 不,.bss 通常用于未初始化和零初始化的静态数据。 y 的存储应该最终位于 .data 段中。 - dfrib

5
在C++中,静态局部变量仅在控制流第一次经过它们的声明时初始化。对于这种情况,y 在调用 main() 后被初始化,并且 x 已经被初始化为值 5,然后 y 也被初始化为 5

只有在控制流第一次经过其声明时才进行初始化。

在C语言中,静态变量是在程序启动前(即在调用 main() 之前)初始化的;y不能从 main() 中的局部变量 x 进行初始化。

其生命周期为整个程序执行期间,其存储的值仅在程序启动前进行一次初始化。


-1

我猜测这是https://en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables的不同编译器解释。

通常,您只能将静态值分配给静态变量。这包括可执行文件的.data部分(例如,所有char*/c-style字符串本质上都是静态的)。

由于x不是静态值,因此gcc正确地发出了投诉。 G++是c++编译器,因此具有与默认情况下的C不同的实现。


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