分类: C/C++
2012-05-01 12:10:43
点击(此处)折叠或打开
2.C程序的存储布局--代码段
代码段是用于存放CPU要执行的指令段。代码段只读,任何对代码段的修改,都会造成段错误。
一个程序在多数情况下是不需要修改自身代码的,只有一种情况例外,就是一些长时间运行的升级程序。
可以采用共享库的形式,来修改一个运行中的程序的代码段。
3.C程序的存储布局--数据段和缓冲段
初始化数据段(.data):也称为数据段。包含初始过的全局变量和静态变量。该段的大小在编译时确定。
未初始化数据段(.bss,block start with symbol):这个段中的数据是程序没有明确初始化的静态变量+全局变量。又叫做块缓存段,块存储段
在elf格式的目标文件中,bss段并不占用实际的空间,而只是一个占位符,已告知指定位置上应当预留全局数据的空间。块缓存段存在的原因是为了提供磁盘上存储空间的利用率。
未初始化数据段不会存储在外存上,在程序运行时,由内核将段中的数据初始化成0或NULL。
4.C程序的存储布局--栈
所有的自动变量+函数调用时所需要保存的信息(返回地址,函数调用前各寄存器的值)都保存在栈中。
每个函数都有对应的栈帧。栈帧在一个函数调用时被创建,在函数调用结束时消亡。所有的函数都是基于进程的栈创建的,从全局的角度来看,一个进程只有一个栈(也只有一个堆),但每个函数执行时,都对应一块独立的栈帧。所以不应该在栈帧上传递一个返回值的地址,因为函数调用结束后,该栈帧有可能会被覆盖掉,相应的,对该地址的引用就会是无效的。
注意:不应该将一个指向局部变量的指针作为返回值返回。在linux环境下,这种方法是错误的。但Windows平台下,似乎是可行的。
函数调用结束后,栈帧上的内容还存在,函数返回的是一个局部变量的地址。如果该栈帧被其他函数覆盖,对该指针的引用也就失效了。
5.C程序的存储布局--堆
堆,用于存储用户申请的内存空间,系统通常在堆中进行动态内存分配。
对于小端处理器,栈地址由高-->低,堆地址由低-->高增长。大端处理器正好相反。
6.常量的存储
C语言中常量有两种:简单常量,如1234,‘c';复杂常量,如iloveyou等字符串常量。
在汇编语言中,对于常量参与运算的C语句,如a+1的汇编代码被汇编成如下:
点击(此处)折叠或打开
简单常量,它随着指令一起存储,也就是说简单变量存储在程序的代码段里。
对于复杂常量,长度不定,放在代码段里面是不明智的,因此编译器将其存储在一个特殊的数据段,将其存储的首地址转换成一个简单变量随着指令存储。这个段叫做.rodata段。
7.动态内存管理
C语言中只能通过malloc和其他派生函数动态申请内存,malloc作为一个库函数,它的linux版本封装了
sbrk()系统调用,该系统调用负责向操作系统申请内存。malloc函数分配的内存在堆中,全局有效。
点击(此处)折叠或打开
做如下改动:
点击(此处)折叠或打开
将fenpei1函数修改为如上形式。传递给fenpei1函数的是int *p的一份拷贝,p在函数返回后就消失了。
这时,p所指向的还是一块未知区域,再对p进行解引用赋值就出错了。