c++ - 为什么局部静态变量是 BSS 段的一部分?

标签 c++ c gcc

静态内存布局的 BSS 部分 [应该] 用于“未初始化的全局变量”或“设置为 0 的全局变量”。

我正在运行一些测试,突然注意到局部静态变量也在增加 BSS 段的大小。

例子:-

在任何静态变量之前

int main (int argc, char argv[])
{
    return 0;
}
data/repos/e-c 
❯ size a.out 
   text   data     bss     dec     hex  filename
   1418    544       8    1970     7b2  a.out

在静态变量之后

int main (int argc, char *argv[])
{
    static int a, b, c;
    return 0;
}
data/repos/e-c 
❯ !s
size a.out 
   text   data     bss     dec     hex  filename
   1418    544      16    1978     7ba  a.out

那些变量肯定不是全局变量,那为什么BSS段会增加呢?或者“未初始化的全局变量的段”的想法不完全正确?

目前我在 Linux 上使用 GCC 编译器(版本 9.3.0)。

最佳答案

The BSS section of the static memory layout is [supposed to be] for "Uninitialized global variables" or "Global variables set to 0".

不清楚您是从哪里得到这种印象的,但这充其量只是一种误导。大多数人在 C 上下文中使用术语“全局变量”是指具有外部链接 的对象标识符,这对于具有静态存储持续时间 的对象来说是必然的。有一些附带条件,这样的标识符可以在程序的任何地方使用来指代同一个对象,因此是“全局的”。一些附带条件的存在和性质使得使用“全局”一词来描述这些条件有点令人担忧,但我会把它留给另一个答案。

关于BSS的关键点不是链接而是存储时长。静态存储持续时间意味着,至少在原则上,对象在程序开始时或之前开始存在*,并且(至少)存在直到程序终止。与在没有 static 的 block 范围内声明的变量对比:它们具有自动存储持续时间,这意味着它们在声明时就存在,并且仅在执行它们的最内层包含时才存在 block 终止。

具有静态存储持续时间的对象需要在程序镜像中表示,而不管它们的链接如何,因为它们与程序本身具有相同的生命周期。 C 指定如果此类对象未显式初始化,则它们的初始值就好像它们被初始化为 0(对于数字类型)或初始化为 NULL(指针类型)或按成员方式初始化为这些复合类型类型。 BSS 是一种节省空间和时间的快捷方式,用于表示此类对象和明确初始化为 0 的对象的存储。

满足初始化条件的所谓“全局”变量可以并且通常归因于 BSS,但也是如此

  • 具有内部链接的文件范围变量(static 对该范围内的声明的影响;这些变量自动具有静态存储持续时间,但只能从一个源文件访问,和
  • 具有静态存储持续时间的 block 范围变量,如在该范围内使用 static 关键字指定的那样,即使这些变量没有链接。

*在 C++ 中,其中一些对象稍后会进行动态初始化,但此类对象的内存仍会在整个程序运行期间保留,并且它们会进行零初始化在程序启动时。为了这个答案的目的,他们保留了内存和明确定义的值(value)构成了存在。

关于c++ - 为什么局部静态变量是 BSS 段的一部分?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66390645/

相关文章:

c++ - 初始化一个内部分配的矩阵

c - struct 中的 int 字段尚未初始化的值是什么?

c - 在文本文件中搜索匹配字符串

c - MinGW/Eclipse C 构建问题 : cannot find dll

c++ - boost::ireplace 是否可以像基本字符一样对待特殊字符? (例如 'ź' 为 'z' )

c++ - Float 到 std::string 的转换和本地化

c++ - C++ 线程中未触及的共享资源

c - 为什么像 memchr 这样的函数绑定(bind)到 C 实现而不是用纯 Rust 编写?

c++ - 使用虚拟继承的类似乎允许基类构造函数覆盖另一个基类的成员

C 程序不再在 Ubuntu 中编译