【问题标题】:Why are local static variables part of the BSS segment?为什么局部静态变量是 BSS 段的一部分?
【发布时间】:2021-05-29 02:51:37
【问题描述】:

静态内存布局的 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)。

【问题讨论】:

  • 嗯,哪里说 BSS 只适用于全局?维基百科说“BSS 段包含所有初始化为零或在源代码中没有显式初始化的全局变量和静态变量。”。
  • static 变量与全局变量具有相同的存储类。
  • @mediocrevegetable1,是和否。 static 对于文件范围声明的含义与对于块范围声明的含义不同。声明的标识符具有内部链接是文件范围的效果。声明的对象具有静态存储持续时间(在文件范围内声明的所有对象都具有,无论是静态的还是外部的)是块范围内的效果。
  • global 在这里是一个误导性的术语。你不像storage duration那样关心访问级别。

标签: c++ c gcc


【解决方案1】:

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

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

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

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

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

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

*在 C++ 中,其中一些会在稍后进行动态初始化,但此类对象的内存仍保留给程序的整个运行,并且它们会进行零初始化在程序启动时。就本答案而言,它们具有内存保留和明确定义的值构成存在。

【讨论】:

  • “静态存储持续时间意味着,至少在原则上,对象在程序开始时或之前存在”,不完全是。静态“全局变量”在调用该 TU 中的第一个函数之前初始化,静态“局部变量”在第一次命中该行代码时初始化:(
  • 不是这样,@MooingDuck,至少在 C 语言中不是这样。我请你参考 C 语言规范的第 6.2.4/3 段:“一个对象,其标识符在没有存储类说明符 _Thread_local 的情况下声明,并且无论是外部链接还是内部链接,或者存储类说明符 static,都具有静态存储持续时间。它的生命周期是程序的整个执行过程,并且它的存储值仅在程序启动之前初始化一次。”
  • @MooingDuck:也很难看出一个实现如何在不产生大量开销的情况下按照自己的方式进行操作 - 使用一种天真的方法,TU 中的每个函数都必须包含要检查的代码(原子地!)如果初始化已经发生,如果没有进行初始化,那么每次调用这些函数时都会执行该代码。
  • @MooingDuck 对于 C++ 基本上是正确的,这清楚地说明了为什么许多双重标记的问题不应该被回答或非常小心地回答。尽管它比这稍微复杂一些,并且从某种意义上说,JohnBollinger 和 MooingDuck 都是正确的,尽管他们似乎在说不同的事情。静态存储持续时间变量通常初始化两次:一次是静态的,根据 6.9.3.2/1“作为程序启动的结果”,一次是动态的。根据 8.8/4 “第一次控制通过其声明”....
  • 动态初始化涉及实际评估初始化程序,在 C++ 中它不必是常量并且可能有副作用。对于局部静态变量,如果包含静态声明的块从未执行过,则不要执行这些副作用是很重要的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-29
  • 1970-01-01
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
相关资源
最近更新 更多