教您布局C言语编程程序的内存
要点重视以下内容:
C言语程序在内存中各个段的组成
C言语程序衔接进程中的特性和常见过错
C言语程序的运转方法
一:C言语程序的存储区域
由C言语代码(文本文件)构成可履行程序(二进制文件),需求通过编译-汇编-衔接三个阶段。编译进程把C言语文本文件生成汇编程序,汇编进程把汇编程序构成二进制机器代码,衔接进程则将各个源文件生成的二进制机器代码文件组合成一个文件。
C言语编写的程序通过编译-衔接后,将构成一个一致文件,它由几个部分组成。在程序运转时又会产生其他几个部分,各个部分代表了不同的存储区域:
1.代码段(Code或Text)
代码段由程序中履行的机器代码组成。在C言语中,程序句子进行编译后,构成机器代码。在履行程序的进程中,CPU的程序计数器指向代码段的每一条机器代码,并由处理器顺次运转。
2.只读数据段(RO data)
只读数据段是程序运用的一些不会被更改的数据,运用这些数据的方法相似查表式的操作,因为这些变量不需求更改,因而只需求放置在只读存储器中即可。
3.已初始化读写数据段(RW data)
已初始化数据是在程序中声明,而且具有初值的变量,这些变量需求占用存储器的空间,在程序履行时它们需求坐落可读写的内存区域内,并具有初值,以供程序运转时读写。
4.未初始化数据段(BSS)
未初始化数据是在程序中声明,可是没有初始化的变量,这些变量在程序运转之前不需求占用存储器的空间。
5.堆(heap)
堆内存只在程序运转时呈现,一般由程序员分配和开释。在具有操作系统的情况下,假如程序没有开释,操作系统或许在程序(例如一个进程)完毕后收回内存。
6.栈(stack)
栈内存只在程序运转时呈现,在函数内部运用的变量、函数的参数以及返回值将运用栈空间,栈空间由编译器主动分配和开释。
C言语方针文件的内存布局
看一个比如:
int a = 0; //大局初始化区,。data段
staTIc int b=20; //大局初始化区,。data段
char *p1; //大局未初始化区 .bss段
const int A = 10; //.rodata段
void main(void)
{
int b; //栈
char s[] = “abc”; //栈
char *p2; //栈
staTIc int c = 0; //大局(静态)初始化区 .data段
char *p3 = “123456”; //123456\0在常量区,p3 在栈上。
p1 = (char*) malloc(10);//分配得来的10和20个字节的区域就在堆区
p2 = (char*) malloc(20);
strcpy(p1, “123456”); //123456\0 在常量区,编译器或许会将它与p3所指向的“123456”优化成一个当地
}
代码段、只读数据段、读写数据段、未初始化数据段归于静态区域,而堆和栈归于动态区域。代码段、只读数据段和读写数据段将在链接之后产生,未初始化数据段将在程序初始化的时分拓荒,而堆和栈将在程序的运转中分配和开释。C言语程序分为映像和运转时两种状况。在编译-衔接后构成的映像中,将只包含代码段(Text)、只读数据段(RO Data)和读写数据段(RW Data)。在程序运转之前,将动态生成未初始化数据段(BSS),在程序的运转时还将动态构成堆(Heap)区域和栈(Stack)区域。一般来说,在静态的映像文件中,各个部分称之为节(SecTIon),而在运转时的各个部分称之为段(Segment)。假如不详细差异,能够统称为段。
知识点:
C言语在编译和衔接后,将生成代码段(Text)、只读数据段(RO Data)和读写数据段(RW Data)。在运转时,除了以上三个区域外,还包含未初始化数据段(BSS)区域和堆(Heap)区域和栈(Stack)区域。
二:C言语程序的段
1.代码段(code或text)
代码段由各个函数产生,函数的每一个句子将终究通过编绎和汇编生成二进制机器代码(详细生生哪种体系结构的机器代码由编译器决议)。
2.只读数据段(RO Data)
只读数据段由程序中所运用的数据产生,该部分数据的特色是在运转中不需求改动,因而编译器会将该数据段放入只读的部分中。C言语中的只读大局变量,只读部分变量,程序中运用的常量等会在编译时被放入到只读数据区。
留意:界说大局变量const char a[100]={“ABCDEFG”};将生成巨细为100个字节的只读数据区,并运用“ABCDEFG”初始化。假如界说为:const char a[ ]={“ABCDEFG”};则依据字符串长度生成8个字节的只读数据段(还有’\0’),所以在只读数据段中,一般都需求做彻底的初始化。
3.读写数据段(RW Data)
读写数据段表明了在方针文件中一部分能够读也能够写的数据区,在某些场合它们又被称为已初始化数据段,这部分数据段和代码段,与只读数据段相同都归于程序中的静态区域,但具有可写性的特色。一般已初始化的大局变量和部分静态变量被放在了读写数据段,如: 在函数中界说staTIc char b[ 100]={“ABCDEFG”};读写数据区的特色是有必要在程序通过初始化,假如只界说,没初始值,则不会生成读写数据区,而会定位为未初始化数据区(BSS)。假如大局变量(函数外部界说的变量)参加static润饰,这表明只能在文件内运用,而不能被其他文件运用。
4. 未初始化数据段(BSS)
与读写数据段相似,它也归于静态数据区,可是该段中的数据没有通过初始化。因而它只会在方针文件中被标识,而不会真实称为方针文件中的一段,该段将会在运转时产生。未初始化数据段只在运转的初始化阶段才会产生,因而它的巨细不会影响方针文件的巨细。
在C言语的程序中,对变量的运用还有以下几点需求留意:
1.函数体中界说的变量一般是在栈上,不需求在程序中进行办理,由编绎器处理。
2.用malloc,calloc,realloc等分配内存的函数所分配的内存空间在堆上,程序有必要确保在运用free开释,不然会产生内存走漏。
3.一切函数体外界说的是大局变量,加了static后的变量不管是在函数内部或外部都放在大局区。
4.运用const界说的变量将放于程序的只读数据区。
三:程序中段的运用
下面用一个简略的比如来阐明C言语中变量和段的对应联系。C言语程序中的大局区(静态区),实践对应着下述几个段:RO Data; RW Data ; BSS Data.
一般来说,直接界说的大局变量在未初始化数据区,假如该变量有初始化则是在已初始化数据区(RW Data),加上const则将放在只读数据区。
const char ro[ ] = {“this is read only data”}; //只读数据区
static char rw_1[ ] ={“this is global read write data”}; //已初始化读写数据段
char BSS_1[ 100]; //未初始化数据段
const char *ptrconst =“constant data”; //字符串放在只读取数据段
int main()
{
short b; //在栈上,占用2个字节
char a[100]; //在栈上拓荒100个字节, 它的值是其首地址
char s[ ]=“abcdefg”; //s在栈上,占用4个字节,“abcdefg”自身放置在只读数据存储区,占8个字节
char *p1; //p1在栈上,占用4个字节
char *p2=“123456”; //p2 在栈上,p2指向的内容不能改,“123456”在只读数据区
static char rw_2[ ]={“this is local read write data”};//部分已初始化读写数据段
static char BSS_2[100]; //部分未初始化数据段
static int c = 0; //大局(静态)初始化区
p1=(char *)malloc(10 * sizeof(char ) ); //分配内存区域在堆区
strcpy(p1,“xxxx”); //“XXXX”放在只读数据区,占5个字节
free(p1); //运用free开释p1所指向的内存
return 0;
}
读写数据段包含了忆初始化的大局变量 static char rw_1[ ]以及部分静态变量static rw_2[ ]。其不同在于编绎时,是在函数内部运用的仍是能够在整个文件中运用。关于rw_1[] 不管有无static 润饰,其都将被放置在读写数据区,仅仅能否被其它文件引证与否。关于后者就不相同了,它是部分静态变量,放置在读写数据区,假如没static润饰,其含义彻底改动,它将会是拓荒在栈空间的部分变量,而不是静态变量,在这里rw_1[],rw_2[]后没详细数值,表明静态区巨细同后边字符串长度决议。
关于未初始化数据区BSS_1[100]与BSS_2[100],其差异在于前者是大局变量,在一切文件中都能够运用;后者是部分变量,只在函数内部运用。未初始化数据段不设置后边的初始化数值,因而有必要运用数值指定区域的巨细,编绎器将依据巨细设置BSS中需求添加的长度。
栈空间首要用于以下3数据的存储:
1.函数内部的动态变量
2.函数的参数
3.函数的返回值
栈空间是动态拓荒与收回的。在函数调用进程中,假如函数调用的层次比较多,所需求的栈空间也逐步加大,关于参数的传递和返回值,假如运用较大的结构体,在运用的栈空间也会比较大。