C++内存分区 static 变量与全局变量的区别 编译单元 COMMON块 .bss段链接前后不一样


C++内存分为:

由于可执行文件在装载时实际上时被映射的虚拟地址空间,所以可执行文件很多时候又被叫做映像文件(Image)

  • 栈区(stack),对应于虚拟内存地址空间中的stack,扩展方向是从高地址到低地址,即使是main函数里头定义的局部变量也是放在栈中,也就是main函数的栈帧中,由编译器自动分配释放 ,存放函数的参数值,局部变量的值等
  • 堆区(heap),对应于虚拟内存地址空间中的heap,扩展方向是从低地址到高地址,一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,malloc或者new申请的内存来自这里
  • 代码区,对应于虚拟内存地址空间中的.text
  • .bss,存放的:未初始化的static变量,初始化为0的全局变量以及static变量,以及“未初始化且为强符号或者是占内存最大的弱符号的全局变量”
  • .data,存放的是初始化了的全局变量和静态变量
  • .rodata,也可以叫文字常量区,存放的是字符串常量,或者是cons修饰的变量

static 变量与全局变量的区别

static 变量只在本源文件中可见,而普通全局变量在所有其他源文件也可见,所以在elf文件中,由于未初始化的全局变量是弱符号,所有先放到COMMON块中,以防在链接的时候发现有同名的强符号,

为什么对于未初始化的全局变量,在.obj文件中不直接放到.bss中呢?

注意COMMON块与.comment不同

  • .comment
  • COMMON块

编译单元

简而言之,一个.obj文件可以看作一个编译单元

首先,C++标准中提到,一个编译单元[translation unit]是指一个.cpp文件以及它所include的所有.h文件,.h文件里的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件,后者拥有PE[Portable Executable,即windows可执行文件]文件格式,并且本身包含的就已经是二进制码,但是,不一定能够执行,因为并不保证其中一定有main函数。当编译器将一个工程里的所有.cpp文件以分离的方式编译完毕后,再由连接器(linker)进行连接成为一个.exe文件。

.bss段链接前后不一样

对于未初始化的全部变量,在链接之前是放在COMMON块中,而链接之后,更具强弱符号的选取,最终把强符号或者是占内存最大的弱符号放到链接后的.bss段中

参考

csdn blog
csdn blog编译单元 模板
施磊老师的课程