C/C++变量在内存中的位置以及初始化问题
首先我们给出内存布局
|
高内存地址 |
栈 |
向下增长,可读可写可执行 |
空洞 |
向上增长 |
堆 |
向上增长,可读可写可执行 |
BSS段(未初始化数据段) |
向上增长,可读可写不可执行 |
.data 数据段 |
向上增长,可读可写不可执行 |
.text 文本段(代码段) |
向上增长,可读可写不可执行 |
|
低内存地址 |
不同类型的变量在内存中的位置:
1,局部变量、函数参数存放在栈上。静态局部变量,并不是在调用函数时分配,在函数返回时释放,而是像全局变量一样静态分配在.data数据段,但它的作用域只在函数中起作用。
2,堆,给动态分配内存使用。
3,全局变量、静态变量位于.data数据段;未初始化变量则位于.bss未初始化数据段。
4,const修饰的全局变量在.rodata只读数据段(const变量在定义时必须初始化,如果未初始化将被设为0或空),只读数据段在和.text同一个segment
5,代码段即存储程序文本。指令指针中的指令就从这里取得。这个段一般是可以被共享的:你可以使用两个编辑器(vi?)来编辑文本,则它们共享一个代码段。
全局变量初始化和未初始化的区别
我们都知道未初始化的静态变量或全局变量将被初始化为空串或0;未初始化的局部变量的值不确定。
全局变量不初始化,则默认为0,存放在.bss数据段中。如int x = 0和int x效果一样的。但是还是有差别的:
编译器在编译的时候针对这两种情况会产生两种符号放在目标文件的符号表中,对于初始化的,叫强符号,未初始化的,叫弱符号。
连接器在连接目标文件的时候,如果遇到两个重名符号,会有以下处理规则:
1、如果有多个重名的强符号,则报错。
2、如果有一个强符号,多个弱符号,则以强符号为准。
3、如果没有强符号,但有多个重名的弱符号,则任选一个弱符号。
基于以上规则,使用以下程序测试
1 #include <stdio.h> 2 3 int global_int; 4 void setInt(); 5 6 int main() 7 { 8 printf(“未初始化全局变量: %d\n”, global_int); 9 setInt(); 10 printf(“改变全局变量: %d\n”, global_int); 11 } 12 13 int global_int; 14 15 void setInt() 16 { 17 global_int = 2; 18 }
以上程序正常运行。如果将第2行和第12行的global_int任意一个初始化,程序也正常运行。但将第2行和第12行的gloal_int都初始化,将会出现:error: redefinition of ‘global_int’;
所以我们尽量初始化全局变量。
除了连接有区别外,它们存储的位置也不一样:初始化的全局变量被保存在data数据段中;而未初始化的全局变量被保存在.bss数据段中。