C语言代码组成 - BSS、Data、Stack、Heap、Code、Const

作者&投稿:鄂之 (若有异议请与网页底部的电邮联系)
~ 一段C语言经过编译连接后,成为一段可以运行的代码,可运行的代码可以分为以下四个部分组成:全局变量/静态变量区、堆、栈、代码区。其中全局变量/静态变量区又分为未初始化变量区和初始化变量区,代码区又分为代码和常量区。即汇总下来,代码可以分为6部分组成,包括:BSS区(未初始化的全局变量/静态变量区)、Data区(实始化的全局变量区)、Stack区(栈区)、heap区(堆区)、Code区(代码区)、const区(常量区)。

一、BSS区和Data区

C语言编程中定义的全局变量、静态局部变量,就是分配在全局变量/静态变量区域,但是为什么又要分为BSS区域和Data区域呢?其实我们在定义全局或者静态变量区,有时我会对它赋初始值,有的又不会赋初始化,比如我们定义的全局变量,初始化的赋值,是怎么样写到变量区域中的,我们定义的静态局部变量,在定义时初始化后,为什么后面函数被调用,又不会再初始化呢?这个局部静态变量是怎么样实始化的,什么时候初始化的?

如果分析编译后的汇编代码,就会发现在代码运行起来后,会有一段给变量赋值的指令,这一段代码,不是我们C代码对应的汇编,而是C编译器生成的汇编译代码,这段代码的作用就是给初始化了的静态变量和全局变量进行初始化。这也是为什么全局/静态变量区域,要分BSS和Data的原因。

二、Stack区

栈是一种先进后出的数据结构,这种数据结构正好完美的匹配函数调用时的模型过程,比如函数f(a)在运行过程中调用函数f(b),f(a)在运行过程中的变量就是分配在栈中,通过在调用f(b)前,会将代码中用到的R0~Rn寄存器的值保存到栈中,同时将函数的传入参数写入到栈中,然后进入f(b)函数,函数f(b)的变量b分配在栈中,当函数运行完毕后,释放变量b,将栈中存放的f(a)函数的运行的R0~Rn寄存器值恢复到寄存器中,同时f(b)的返回结果存入到栈中,这样f(a)继续运行。当一个函数运行完毕后,它在栈中分配的临时变量会全部释放。

对于中断也是一样的,中断发生时,也是一个函数打断了另一个函数的运行,这种现场的保存(即寄存器的值),都是通过栈来完成的。所以栈的作用有:

三、Heap区

全局变量分配的内存在代码整个运行周期内都是有效的,而在栈区分配的内存在函数调用完成后,就会释放。这两种内存模型都是由编译器决定它的使用,代码是无法控制的。那有没有内存是由用户控制的,要用时,就自由分配,不用时,就自行释放?答案是肯定的,这部分内存就是堆。

用户需要使用的动态内存,就是通过malloc函数,调用分配的,在没有释放前,可一直由代码使用。当这部分内存不再需要使用时,可以通过free函数进行释放,将它归还到堆中。从这中可以看出,堆的内存,是按需分配的。这就是赋予了代码很大的自由度,但这也是会带来负作用的,比如:内存碎片化导致的malloc失败;忘记释放内存导致的内存泄露,而这些往往是致命的失误。

四、Code区

代码区就是编译后机器指令,这些指令决定了功能的执行。我们编译的代码一般是下载进flash中,但是运行,却有两种方式:在RAM中运行和在ROM中运行。 在RAM中运行,即是boot启动后,将flash中的代码复制到RAM中,然后PC指针在指到RAM中的代码中开始运行。 有时在调试时,我们可以直接将代码下载进RAM中运行进行调试,这样加快调试速度。便是大部分的情况我们的代码是从flash中开始运行的。

五、常量区

代码中的常量,一部分是作为立即数,在代码区中,但是像定义的字符串、给某数组赋值的一串数值,这些常量,就存在常量区,我们常用const来定义一个常量,即该变量不能再必变。这部分的变量,编译器一般将它定义的flash中。

六、各个区域大小的是如何决定的:

code区和const区:是由代码的大小和代码中常量的多少来决定的。

bss区和data区:这是由代码中定义的全局变量和局部变量的多少来决定的。

stack区:这个可以由使用都自行定义大小,但使用都要根据自已代码的情况,评估出一个合理的值,再定义其大小,如果定义的太小,很容易爆栈,导至代码异常,但是如果定义的太大,就容易浪费内存。

heap区:RAM剩下的部分,编译器就会作为堆区使用。

七、嵌入式代码一般启动过程

以STM32为例,通过分析其汇编启支代码,大致可以分为以下几个步骤:

如果大家想看编译扣,代码文件的组成,可以查看统后生的map文件,里面有详细的数据,包括各个函数的分配内存,BSS,Data,Stack,Heap,Text的分配情况。

如果相要了解详细的代码启动过程,可看它的启动汇编文件。


海阳市17536366188: 内存里的bss是什么?
亓飞脑立: 你说的应该是C语言里的东西吧.BSS的英文全称叫Block Started by Symbol,它是用来存放C程序中未初始化的全局变量和静态变量的内存空间.虽然未初始化,但程序运行时里面的数据值会自动设置为0.

海阳市17536366188: C语言实现读取.dat或.txt的数据并赋值给一个real变量
亓飞脑立: 你只有一个数据,不需要循环读. float velocity; FILE *fp; fp=fopen("tmp.dat","r"); fscanf(fp,"%f",&velocity); fclose(fp); 就可以了. double velocity; 则用 格式 %lf -- fscanf(fp,"%lf",&velocity); 数据传递可以通过全局量: float...

海阳市17536366188: 一个C语言程序(阶梯型收水费) -
亓飞脑立: 错误的行在y=n*3.5*3.7+n*3.5*(1.2-1)*3.7*2+n*3.5(1.4-1.2)*3.7*3+(t-n*3.5*(1+0.4))*3.7*4; !!改为y=n*3.5*3.7+n*3.5*(1.2-1)*3.7*2+n*3.5*(1.4-1.2)*3.7*3+(t-n*3.5*(1+0.4))*3.7*4;n*3.5(1.4-1.2)*3.7*3中3.5(1.4-1.2)之间漏掉了*

海阳市17536366188: c语言中一个关于dat文件究竟怎么一回事啊 -
亓飞脑立: 1.不用空隔符作间隔是因为输入到文件的内容没有用空隔符作间隔.2.str[80]不大,这个叫"接收缓冲",一般设置是实际内容长度的2倍以上.3.ch[4]=0和ch[5]=0是给ch这个字符串添加结尾符'\0',一般专业人 员写的话就写为:ch[4]=0x0和ch[5]=0x0,是一样的效果.4.实际上用二进制的方式写入和读取文件更方便,不需要作转换.

海阳市17536366188: 哈夫曼编码的C语言源代码 -
亓飞脑立: 原发布者:丁丁的23号/*先根据位权构造一颗哈夫曼树,测试数据0.050.10.150.20.250.25,再从叶子结点到根结点编码.程序结果保存在out.dat中.*/#include#include#include#defineN6typedefstruct{doubleweight;intparent,lchild,rchild;}...

海阳市17536366188: BSS段(bss segment)是C语言中的内容还是汇编语言中的内容啊 -
亓飞脑立: 是程序的段式内存管理的内容,一般bss, data,text 段.网上查一下吧

海阳市17536366188: C语言程序编程 -
亓飞脑立: #include#include#define SIZE 100int num[SIZE+1];void WriteDat(){ FILE *fp; int count=0,i; if((fp=fopen("OUT.Dat","wb"))==NULL) { printf...

海阳市17536366188: c语言编程:求一个生成200个4位随机正整数并输出到in.dat文件中的的代码. -
亓飞脑立: #include #include int main() { FILE *fp; fp=fopen("in.dat","w"); srand((unsigned)time(NULL)); for(int i=0;i!=200;++i) { int j; do { j=rand(); }while(j>=9999||j<=1000); fprintf(fp,"%d\n",j); } return 0; } 写好了楼主,你看看吧

海阳市17536366188: C语言编程:从键盘输入一些字符,逐个将它们送到文本文件“tt.dat”中,直到输入一个”#“为止. -
亓飞脑立: #include <stdio.h> void main(void) { FILE *fp; char c; fp=fopen("tt.dat","w"); c=getchar(); while(c!='#') { fputc(c,fp); c=getchar(); } fclose(fp); }

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网