C程序(进程)的内存布局

来源:互联网 发布:如何让淘宝店铺排名靠前 编辑:程序博客网 时间:2024/04/29 21:29
复制代码
#include <stdio.h>const int a = 10; //全局常量aint main(void) {  const int b = 20; //局部常量b  int* pa = (int*)&a;  int* pb = (int*)&b;  *pa = 30; //可以吗?能成功赋值吗?  *pb = 30; //可以吗?能成功赋值吗?  return 0;}
复制代码

作为编程新手的我,有时候写程序难免会有种迷糊的感觉,虽然写着代码,但总觉得哪里不自在不通透...像上面的代码,我第一次看到的时候根本没有自信回答出来,我觉着应该有不少编程新人和我一样吧>o<

 

先从(Linux平台下)虚拟内存管理说起,

  写C程序时,我们经常会打印一个指针地址,说这个指针指向某某内存地址.可这些地址是真实物理内存地址吗?不是!这些只是虚拟内存地址.

  当一个C程序调入内存开始执行后,在内存中就会产生一个进程.而在多任务操作系统中每个进程都拥有一片属于自己的内存空间(内存沙盘),这个沙盘就是虚拟地址空间,在32位下是一个4GB的大小的地址块,这些虚拟地址通过页表映射到物理内存.

  但系统并不会真的一下分配给每一个进程4GB的物理内存空间的映射=  =(不现实啊),这4GB只能是说逻辑地址,它会随着进程的真实需要自动扩展映射到物理内存空间,最大到4GB.

  4GB(地址0-0xFFFFFFFF)其中1GB必须保留给系统内核(这是Linux平台下),也就是说进程自身只能拥有3GB的地址(0-0xC0000000),如图

我自己画的=  =:

  代码区:程序(函数)代码所在,由编译而得到的二进制代码被载入至此.代码区是只读的!有执行权限.代码区一般都从0x08048000地址开始(linux下).值得注意的是,字符串字面值(如"Hello World")就存储在这个区.

  数据段BSS段:合称静态区(全局区),用来存储静态(全局)变量.区别是 前者(数据段)存储的是已初始化的静态(全局)变量,可读写. 

后者(BSS段)存储的是未初始化的静态(全局)变量,可读写.

  堆:自由存储区.不像全局变量和局部变量的生命周期被严格定义,堆区的内存分配和释放是由程序员所控制的.申请方式:C中是malloc函数,C++中是new标识符.

  栈:由系统自动分配和释放.存储局部(自动)变量. 一般说的堆栈,其实是指 栈!

  另外,值得注意的是,是由低地址向高地址分配空间;却是由高地址向低地址分配空间.

下面这段代码进一步说明C程序中各数据的内存布局:

复制代码
#include <stdio.h>#include <stdlib.h>int i1 = 10; //静态全局区(data段)int i2; //静态全局区(bss段)static int i3 = 30; //静态全局区(data段)const int i4 = 40;  //代码区!!!void fun(int i5) //栈区{    int i6 = 60; //栈区    static int i7 = 70; //静态全局区(data段)    const int i8 = 80; //栈区!!!    char* str1 = "ABCDE"; //代码区(字符串常量)    char str2[] = "ABCDE"; //栈区(字符数组)    int* pi = malloc(sizeof(int)); //堆区    printf("&i5=%p\n", &i5);    printf("&i6=%p\n", &i6);    printf("&i7=%p\n", &i7);    printf("&i8=%p\n", &i8);    printf("str1=%p\n", str1);    printf("str2=%p\n", str2);    printf("pi=%p\n", pi);    free(pi);}int main(void){    printf("&i1=%p\n", &i1);    printf("&i2=%p\n", &i2);    printf("&i3=%p\n", &i3);    printf("&i4=%p\n", &i4);    fun(50);    return 0;}
复制代码

 

(gcc编译)程序输出:

 

至此,从地址大小比较可以看出

1)静态(static)全局变量 和 静态(static)局部变量 都在 静态全局区.

2)全局常量i4保存在代码区,而局部常量i8保存在栈区.

所以最上面的问题是,代码区只读,修改全局常量会引发运行时段错误,而局部常量是可以成功赋值修改的.

3)字符串字面值在代码区(所以不可修改),但是字符指针str1在栈区;字符数组str2在栈区(所以可以修改).

 

最后要说,上述是Linux下的虚拟内存布局顺序,Windows下会有所不同.但是对于C程序中数据应该存储在哪里都是一致的.

注:我在自己的Ubuntu 12.04 32位上运行了上面的两个程序,程序一可以生成可执行文件,运行会有段错误,但是此时两个常量的角色一个是全局的,一个是局部的,全局常量在代码区中,局部常量在栈中,代码区可读不可写,栈区可读可写,将*pa = 30;注释掉后,程序可以运行成功,而且b的值也被修改了,第二个程序和原作者的结果类似,特别是静态全局区完全相同,其实还是有些不解,为啥全局静态变量会放在代码区,还有C程序运行环境背后是怎么支持的,不解。


热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 宜家水壶盖子有水怎么办 背滤鱼缸除油膜怎么办 书多了没地方放怎么办 学生在教室内丢手机怎么办 新车尾箱坏了怎么办 放书的箱子烂了怎么办 车钥匙锁后备箱里怎么办 布的收纳箱有味怎么办 车漆清漆层掉了怎么办 副驾驶储物箱卡子断了怎么办 玛莎拉蒂车门打不开怎么办 新买的水杯漏水怎么办 泰迪小狗掉毛怎么办 手机jlc调用接口状态异常怎么办 进门和厕所对着怎么办 p过的照片有竖条怎么办 当照片p出竖条纹怎么办 月子里落下脚心怕风怕凉怎么办 鞋胶把手粘住了怎么办 凉鞋魔术贴长了怎么办 新买的狗一直叫怎么办 刚买的幼犬老叫怎么办 狗狗什么都不吃怎么办 新买的吊扇风小怎么办 夜市卖果汁没电怎么办 榻榻米太长2米45怎么办 木质桌子黏黏的怎么办 白色塑料桌子染色了怎么办 3dmax模型变透明了怎么办 刚养的兔子不吃怎么办 熊猫兔不吃下喝怎么办 熊猫兔感冒了一直打喷嚏怎么办 兔子后腿骨断了怎么办 兔子的腿肿了怎么办 仓鼠喝了牛奶该怎么办 宠物兔不吃不喝怎么办 兔子把木屑吃了怎么办? 小车司机碰瓷大车司机怎么办 在淘宝买到假的护肤品怎么办 淘宝购物发现是假的怎么办 电脑键盘灯不亮不能打字怎么办