我正在读这篇关于C程序内存布局的精彩帖子.它表示默认初始化全局变量驻留在BSS段中,如果您明确地为全局变量提供值,那么它将驻留在数据段中.
我已经在C和C++中测试了以下程序来检查这种行为.
#include// Both i and s are having static storage duration int i; // i will be kept in the BSS segment, default initialized variable, default value=0 int s(5); // s will be kept in the data segment, explicitly initialized variable, int main() { std::cout<<&i<<' '<<&s; }
输出:
0x488020 0x478004
因此,从输出中可以看出,变量i和s都存在于完全不同的段中.但是如果我从变量S中删除初始化程序(此程序中的初始值为5)然后运行程序,它会给我以下输出.
输出:
0x488020 0x488024
因此,从输出中可以清楚地看出变量i和s都位于相同的(在这种情况下为BSS)段中.
这种行为在C中也是一样的.
#includeint i; // i will be kept in the BSS segment, default initialized variable, default value=0 int s=5; // s will be kept in the data segment, explicitly initialized variable, int main(void) { printf("%p %p\n",(void*)&i,(void*)&s); }
输出:
004053D0 00403004
因此,我们可以再次通过查看输出(意味着检查变量的地址)来说,变量i和s都位于完全不同的段中.但是,如果我从变量S中删除初始化程序(此程序中的初始值5)然后运行程序,它会给我以下输出.
输出:
004053D0 004053D4
因此,从输出中可以清楚地看出变量i和s都位于相同的(在这种情况下为BSS)段中.
为什么C和C++编译器将显式初始化和默认初始化全局变量放在不同的段中?为什么全局变量在默认初始化变量和显式初始化变量之间存在区别?如果我没有错,那么C和C++标准从不谈论堆栈,堆,数据段,代码段,BSS段以及所有特定于实现的事情.那么,C++实现是否有可能将显式初始化和默认初始化变量存储在相同的段中,而不是将它保存在不同的段中?
语言C或C++都没有"段"的概念,也不是所有操作系统都这样做,所以你的问题不可避免地依赖于平台和编译器.
也就是说,常见的实现方式将以不同方式处理初始化变量与未初始化变量.主要的区别是,未初始化(或默认为0初始化)数据并没有必须实际保存与编译的模块,而只是宣称/保留在运行时以后使用.在实际的"段"条款,初始化的数据被 保存到磁盘作为二进制文件的一部分,同时未初始化的数据是不是,而是它在启动时分配给满足宣布"保留".
真正简短的回答是"因为它占用的空间更少".(正如其他人所说,编译器不必这样做!)
在可执行文件中,该data
部分将包含其值存储在相对位置的数据.这意味着对于初始化数据的每个字节,该数据部分包含一个字节.
对于零初始化的全局变量,没有理由存储大量的零.相反,只需将整个数据集的大小存储在一个单一的大小值中.因此,不是在seciton中存储4132个字节的零,data
而是"BSS长度为4132个字节" - 并且由OS /运行时设置以使其为零.- 在某些情况下,编译器的运行时将memset(BSSStart, 0, BSSSize)
或类似.在例如Linux中,无论如何在创建进程时所有"未使用"的存储器都填充为零,因此将BSS设置为零只是首先分配存储器的问题.
当然,较短的可执行文件有几个好处:硬盘上占用的空间更少,加载时间更短[如果操作系统预先填充分配的内存为零,则额外奖励],编译器/链接器没有更快的编译时间必须将数据写入磁盘.
所以这有一个完全实际的原因.
根据定义,BSS不是一个不同的部分,它是数据部分的一部分.
在C和C++中,没有显式初始化器的静态分配对象被初始化为零,实现还可以为BSS部分分配静态分配的变量和用仅由零值位组成的值初始化的常量.
将它们存储在BSS中的原因是,可以在运行时获得具有未初始化或默认值的那些类型的变量而不浪费二进制文件中的空间而不是放置在数据段中的变量.