我所知道的是,全局和静态变量存储在.data
段中,未初始化的数据位于.bss
段中。我不明白的是为什么我们有未初始化变量的专用段?如果未初始化的变量在运行时分配了值,该变量是否仅存在于.bss
段中?
在以下计划中,a
位于.data
段,b
位于.bss
段;那是对的吗?如果我的理解是错误的,请纠正我。
#include <stdio.h>
#include <stdlib.h>
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
int b[20]; /* Uninitialized, so in the .bss and will not occupy space for 20 * sizeof (int) */
int main ()
{
;
}
另外,请考虑以下程序,
#include <stdio.h>
#include <stdlib.h>
int var[10]; /* Uninitialized so in .bss */
int main ()
{
var[0] = 20 /* **Initialized, where this 'var' will be ?** */
}
答案 0 :(得分:77)
原因是减少了程序大小。想象一下,您的C程序在嵌入式系统上运行,其中代码和所有常量都保存在真正的ROM(闪存)中。在这样的系统中,在调用main()之前,必须执行初始“copy-down”以设置所有静态存储持续时间对象。它通常会像这样伪:
for(i=0; i<all_explicitly_initialized_objects; i++)
{
.data[i] = init_value[i];
}
memset(.bss,
0,
all_implicitly_initialized_objects);
其中.data和.bss存储在RAM中,但init_value存储在ROM中。如果它是一个段,则ROM必须填充大量的零,从而显着增加ROM大小。
基于RAM的可执行文件的工作方式类似,但当然它们没有真正的ROM。
此外,memset可能是一些非常有效的内联汇编程序,这意味着可以更快地执行启动副本。
答案 1 :(得分:74)
.bss
段是优化。整个.bss
段由单个数字描述,可能是4个字节或8个字节,在运行过程中给出了它的大小,而.data
部分与初始化的大小之和一样大变量。因此,.bss
使可执行文件更小,更快地加载。否则,变量可以在.data
段中,显式初始化为零;该计划将难以分辨出来。 (详细地说,.bss
中对象的地址可能与.data
段中的地址不同。)
在第一个程序中,a
将位于.data
段中,b
将位于可执行文件的.bss
段中。加载程序后,区别变得无关紧要。在运行时,b
占用20 * sizeof(int)
个字节。
在第二个程序中,var
被分配了空格,main()
中的分配修改了该空格。恰好在var
段而不是.bss
段中描述了.data
的空间,但这不会影响程序在运行时的行为方式。
答案 2 :(得分:11)
Jeff Duntemann致Assembly Language Step-by-Step: Programming with Linux关于 .data 部分:
.data 部分包含初始化数据项的数据定义。初始化 数据是在程序开始运行之前具有值的数据。这些价值观 是可执行文件的一部分。当它们被加载到内存中 可执行文件被加载到内存中以供执行。
关于.data部分要记住的重要事情是 您定义的初始化数据项越多,可执行文件越大 将来,将它从磁盘加载到内存所需的时间越长 当你运行它时。
和 .bss 部分:
在程序开始运行之前,并非所有数据项都需要具有值。 例如,当您从磁盘文件中读取数据时,您需要有一个 从磁盘进入后数据的位置。像这样的数据缓冲区 在程序的 .bss 部分中定义。你预留了一些 缓冲区的字节并给缓冲区一个名称,但是你没有说出什么值 将存在于缓冲区中。
.data中定义的数据项之间存在重要差异 .bss部分中定义的部分和数据项:中的数据项 .data部分添加到可执行文件的大小。数据项目 .bss部分没有。一个占用16,000字节(或更多, 有时甚至更多)可以在.bss中定义,几乎不添加任何内容 (对于描述大约50个字节)到可执行文件大小。
答案 3 :(得分:9)
嗯,首先,你的例子中的那些变量不是未初始化的; C指定未初始化的静态变量初始化为0。
因此.bss的原因是拥有较小的可执行文件,节省空间并允许更快地加载程序,因为加载器可以只分配一堆零而不必从磁盘复制数据。
运行程序时,程序加载程序会将.data和.bss加载到内存中。写入驻留在.data或.bss中的对象,因此只能进入内存,它们不会在任何时候刷新到磁盘上的二进制文件。
答案 4 :(得分:3)
维基百科文章.bss提供了一个很好的历史解释,因为该术语来自1950年代中期(yippee my birthday; - )。
在当天,每一点都很珍贵,所以任何信号保留空白空间的方法都很有用。这个( .bss )就是卡住的那个。
.data 部分用于非空的空间,而是输入(您的)定义的值。
答案 5 :(得分:3)
System V ABI 4.1 (1997) (AKA ELF规范)也包含答案:
.bss
此部分包含有助于实现此目标的未初始化数据 程序的记忆图像。根据定义,系统初始化 程序开始运行时带零的数据。该部分不占用文件空间,如部分类型SHT_NOBITS
所示。
表示部分名称.bss
是保留的并且具有特殊效果,特别是不占用文件空间,因此优于.data
。
缺点当然是当操作系统将它们放在内存上时,所有字节都必须设置为0
,这是一个更具限制性但是常见的用例,并且适用于未初始化的变量。
SHT_NOBITS
部分类型文档重复了这一肯定:
sh_size
该成员给出了部分的大小(以字节为单位)。除非秒 类型为SHT_NOBITS
,该部分占用sh_size
文件中的字节数。类型SHT_NOBITS
的部分可能具有非零值 大小,但它在文件中不占用空间。
C标准对部分没有任何说明,但是我们可以使用objdump
和readelf
轻松验证变量在Linux中的存储位置,并得出结论:未初始化的全局变量实际上存储在{{1例如,请参阅此答案:https://stackoverflow.com/a/36725211/895245