C语言编程程序的内存怎样布局

在c语言中,每一个变量和函数有两个属性:数据类型数据的存储类别

C语言中局部变量和全局变量变量的存储类别(static,extern,auto,register)

1. 从变量的作用域划分变量(即从空间)角度来分

1.全局变量
2.局部变量

2. 从变量值存在的时间或存储类别(即生存期)角度来分

2.1. 静态存储区

存放下面数据: 代码段(text)仅仅读数据段(rodata)读写数据段(rwdata)未初始化数据段(bbs)

静态存储区存放所有的全局变量, 这些变量将在链接之后产生, 程序执行完成就释放, 程序执行的过程中它们占领固定的存储单元, 而不会动态的进行分配和释放

2.2. 动态存储区

存放下面数据: 函数形參自己主动变量(未加static声明的局部变量)函数调用时的现场保护和返回地址

对以上这些数据,在函数開始调用时分配动态存储空间。函数结束时释放这些空间。

3. 从用户内存空间角度分为三个部分

1. 程序区
一行一行的等待执行的机器码
2. 静态存储区
3. 动态存储区

4. 从C程序执行时又可分为下面存储区

1. 代码段 (Code | Text)

代码段由程序中执行的机器代码组成。

在C语言中。程序语句进行编译后,形成机器代码。在执行程序的过程中,CPU的程序计数器指向代码段的每一条机器代码。并由处理器依次执行。

2. 仅仅读数据段(ROData)

2.1 ROData介绍
  1. 仅仅读数据段是程序使用的一些不会被更改的数据,使用这些数据的方式相似查表式的操作。因为这些变量不须要更改,因此仅仅须要放置在仅仅读存储器中就可以。
  2. 仅仅读数据段由程序中所使用的数据产生,该部分数据的特点是在执行中不须要改变,因此编译器会将该数据段放入仅仅读的部分中。C语言中的仅仅读全局变量仅仅读局部变量。程序中使用的常量等会在编译时放入仅仅读数据区
  3. 注意:定义全局变量const char a[100]={“ABCDEFG”};将生成大小为100个字节的仅仅读数据区,并使用“ABCDEFG”初始化。

    假设定义为:const char a[ ]={“ABCDEFG”};则依据字符串长度生成8个字节的仅仅读数据段(还有’\0’),所以在仅仅读数据段中,一般都须要做全然的初始化。

2.2 Example
#define A=18;       ##常量

const int A = 18;     ##仅仅读全局变量
int main(){
    const int B = 18;     ##仅仅读局部变量
}

3. 已初始化读写数据段(RW data)

3.1 RWData介绍
  1. 已初始化数据是在程序中声明,而且具有初值的变量。这些变量须要占用存储器的空间。在程序执行时它们须要位于可读写的内存区域内。并具有初值。以供程序执行时读写。
  2. 全局变量所有存放在静态存储区,在程序開始执行时给全局变量分配存储区程序行完成就释放。在程序执行过程中它们占领固定的存储单元而不动态地进行分配和释放

全局变量

静态(static) 局部变量

3.2 Example
int global_init_val=1;                   ## 全局变量
int main(int argc, char * argv[]){
    static int a=1;                      ## 静态(static) 局部变量
}

4. 未初始化数据段(BSS)

4.1 BSS介绍

未初始化数据是在程序中声明,可是没有初始化的变量,这些变量在程序执行之前不须要占用存储器的空间。

4.1 Example
int global_noinit_val;                   ## 全局未初始化全局变量
char *p1;                                ## 全局未初始化全局变量

int main(int argc, char * argv[]){
    ......
}

5. 堆(heap)

5.1 堆空间介绍

堆内存仅仅在程序执行时出现。一般由程序猿分配释放

在具有操作系统的情况下,假设程序没有释放操作系统可能在程序(比如一个进程)结束后回收内存

5.2 Example
p1 = (char*) malloc(10);     ## 分配得来的10和20个字节的区域就在堆区
p2 = (char*) malloc(20);

6. 栈(stack)

6.1 栈空间介绍
  1. 栈内存仅仅在程序执行时出现。在函数内部使用的变量函数的參数以及返回值使用栈空间,
  2. 栈空间由编译器自己主动分配和释放。

  3. 栈空间动态开辟回收的。在函数调用过程中,假设函数调用的层次比較多,所须要的栈空间也逐渐加大
  4. 对于參数的传递返回值,假设使用较大的结构体,在使用的栈空间也会比較大
6.2 栈区主要用于下面数据的存储
  1. 函数内部的动态变量
  2. 函数的參数
  3. 函数的返回值
6.3 Example
void main(void){
  int b;                    ## 栈
  char s[] = "abc";         ## 栈
  char *p2;                 ## 栈
  char *p3 = "123456";      ## 123456\0在常量区  ## p3 在栈上。
}

===================================华丽的切割线=========================

5. 4种局部变量和全局变量的存储类别(static, extern, auto, register)

5.1 Static

有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,这时就应该指定局部变量为“静态局部变量”,用关键字static进行声明。

int f(int a)
{
    auto int b=0;
    static int c=3;
    b=b+1;
    c=c+1;
    return(a+b+c);
}
int main(void)
{
    int a=2,i;
    for(i=0;i<3;i++)
         printf("%d",f(a));
}

对静态局部变量的说明:

1)静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个执行期间都不释放。而自己主动变量(即动态局部变量)属于动态存储类别。占动态存储空间,函数调用结束后即释放。

2)静态局部变量在编译时赋初值,即仅仅赋初值一次;而对自己主动变量赋初值是在函数调用时进行,每调用一次函数又一次给一次初值。相当于执行一次赋值语句。

3)假设在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自己主动赋初值0(对数值型变量)或空字符(对字符变量)。而对自己主动变量来说,假设不赋初值则它的值是一个不确定的值。

5.2 Extern

外部变量即全局变量)是在函数的外部定义的。它的作用域为从变量定义处開始,到本程序文件的末尾。假设外部变量不在文件的开头定义,其有效的作用范围仅仅限于定义处到文件终了。假设在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字extern对该变量作“外部变量声明”。

表示该变量是一个已经定义的外部变量。有了此声明。就能够从“声明”处起。合法地使用该外部变量

int max(int x,int y)
{
    int z;
    z=x>y?x:y;
    return(z);
}
int main(void)
{
    extern A,B;
    printf("%d\n",max(A,B));
}
int A=13,B=-8;

说明:

在本程序文件的最后1行定义了外部变量A。B,但因为外部变量定义的位置在函数main之后,因此本来在main函数中不能引用外部变量A,B。如今我们在main函数中用extern对A和B进行“外部变量声明”,就能够从“声明”处起,合法地使用该外部变量A和B。

5.3 Auto

函数中的局部变量。如不专门声明为static存储类别,都是动态地分配存储空间的。数据存储在动态存储区中

函数中的形參和在函数中定义的变量(包括在复合语句中定义的变量),都属此类,在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自己主动释放这些存储空间。这类局部变量称为自己主动变量。自己主动变量用关键字auto作存储类别的声明。

int f(int a)         /*定义f函数,a为參数*/
{
    auto int b,c=3;     /*定义b,c自己主动变量*/
}

a是形參,b,c是自己主动变量,对c赋初值3。执行完f函数后,自己主动释放a。b,c所占的存储单元。

关键字auto能够省略,auto不写则隐含定为“自己主动存储类别”,属于动态存储方式

占用栈空间

5.4 Register

为了提高效率,C语言同意将局部变量得值放在CPU中的寄存器中,这样的变量叫“寄存器变量”,用关键字register作声明。

int fac(int n)
{
    register int i,f=1;
    for(i=1;i<=n;i++)
        f=f*I;
     return(f);
}
int main(void)
{
    int i;
    for(i=0;i<=5;i++)
        printf("%d!=%d\n",i,fac(i));
}

说明:

1) 仅仅有局部自己主动变量和形式參数能够作为寄存器变量

2)一个计算机系统中的寄存器数目有限,不能定义随意多个寄存器变量

3)局部静态变量不能定义为寄存器变量

6. 总结

  1. 从变量的作用域(即从空间)角度来,能够分为全局变量局部变量
  2. 从变量值存在的作时间(即生存期)角度来,能够分为静态存储方式和动态存储方式。
  3. 代码段仅仅读数据段读写数据段未初始化数据段属于静态区域

    静态区域: 是指在程序执行期间分配固定的存储空间的方式

  4. 属于动态区域

    动态区域: 是在程序执行期间依据须要进行动态的分配存储空间的方式。

  5. 代码段仅仅读数据段读写数据段在链接之后产生
  6. 未初始化数据段在程序初始化的时候开辟
  7. 在程序的执行中分配和释放
  8. C语言程序分为映像执行时两种状态。

    在编译-连接后形成的映像中,将仅仅包括代码段(Text)仅仅读数据段(RO Data)读写数据段(RW Data)

  9. 程序执行之前。将动态生成未初始化数据段(BSS)
  10. 程序的执行时还将动态形成堆(Heap)区域和栈(Stack)区域。

    一般来说,在静态的映像文件里,各个部分称之为节(Section),而在执行时的各个部分称之为段(Segment)。假设不具体区分,能够统称为

  11. C语言在编译和连接后,将生成代码段(Text)、仅仅读数据段(RO Data)和读写数据段(RW Data)。

    执行时,除了以上三个区域外,还包括未初始化数据段(BSS)区域和堆(Heap)区域和栈(Stack)区域。

7. 一些实例

   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中须要添加的长度。

參考文章

深入探讨C语言中局部变量与全局变量在内存中的存放位置

C语言编程程序的内存怎样布局

原文地址:https://www.cnblogs.com/zhchoutai/p/8318451.html

时间: 2024-11-10 07:28:06

C语言编程程序的内存怎样布局的相关文章

C语言编程程序的内存如何布局

重点关注以下内容: C语言程序在内存中各个段的组成 C语言程序连接过程中的特性和常见错误 C语言程序的运行方式 一:C语言程序的存储区域 由C语言代码(文本文件)形成可执行程序(二进制文件),需要经过编译-汇编-连接三个阶段.编译过程把C语言文本文件生成汇编程序,汇编过程把汇编程序形成二进制机器代码,连接过程则将各个源文件生成的二进制机器代码文件组合成一个文件. C语言编写的程序经过编译-连接后,将形成一个统一文件,它由几个部分组成.在程序运行时又会产生其他几个部分,各个部分代表了不同的存储区域

教您布局C语言编程程序的内存

重点关注以下内容: C语言程序在内存中各个段的组成 C语言程序连接过程中的特性和常见错误 C语言程序的运行方式 一:C语言程序的存储区域 由C语言代码(文本文件)形成可执行程序(二进制文件),需要经过编译-汇编-连接三个阶段.编译过程把C语言文本文件生成汇编程序,汇编过程把汇编程序形成二进制机器代码,连接过程则将各个源文件生成的二进制机器代码文件组合成一个文件. C语言编写的程序经过编译-连接后,将形成一个统一文件,它由几个部分组成.在程序运行时又会产生其他几个部分,各个部分代表了不同的存储区域

C语言编程入门——动态内存分配

内存管理,是指软件运行时对计算机内存资源的分配和使用的技术.其最主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源.内存管理是C语言编程中重要的组成部分,C语言中的内存需要手动分配,手动释放,一般遵循分配多少,释放多少,以免造成内存泄漏.内存管理是一项重要且复杂的事情,理解内存管理,对后面课程及项目的学习会有很大的作用. 之前创建变量,是系统自动分配的内存,放在栈内存中,销毁后被系统自动回收,手动分配的内存,放在堆内存中,需要手动释放.千万不要忘记销毁对象手动将内存释放并将指针

C语言应用程序的内存图

1.综述 c语言应用程序加载到内存,这时它所占据的内存分为四个区,分别为栈Stack,堆Heap,静态存储区Static Area,代码存储区Code Area,这四个区分别放置应用程序的不同部分,从而便于操作系统管理. 2.Windows应用程序内存图如下

C语言之程序中内存的来源:栈 堆 数据段

程序在运行的时候,其内存的来源主要通过三种方法:  栈  堆  数据段,总体上来讲栈是一般用来存放小内存的局部变量,堆内存和数据段的属性很像,在使用的的时候,如果这个变量是伴随程序一直存在则使用全局变量,也就是放在数据段,如果一个变量使用完了就没用了,那么就适合用堆内存(先申请,然后释放即可), 一:栈(stack): 1:栈在使用的时候是编译器自动分配内存空间的,不需要程序员的干涉,其次栈的大小是有限的,所以当我们定义的变量需要大片的内存的时候就不适合使用栈, 2:栈存放的是普通变量,栈的在使

C语言程序的内存布局

一:C语言程序的存储区域 C语言编写的程序经过编绎-链接后,将形成一个统一的文件,它由几个部分组成,在程序运行时又会产生几个其他部分,各个部分代表了不同的存储区域: 1.代码段(Code or Text): 代码段由程序中的机器码组成.在C语言中,程序语句进行编译后,形成机器代码.在执行程序的过程中,CPU的程序计数器指向代码段的每一条代码,并由处理器依次运行. 2.只读数据段(RO data): 只读数据段是程序使用的一些不会被更改的数据,使用这些数方式类似查表式的操作,由于这些变量不需要更改

C语言-第31课 - 程序的内存布局

第31课 - 程序的内存布局 代码在可执行程序中有如下的对应关系 有初始值的放在data段,没有初始的放在bss段.静态存储区就对应了这两个区域. 我们写的函数,可移执行的代码段,放在text段. 这里并不见堆和栈的踪影,因为这只是我们的可执行文件的布局,并不会我们执行起来,进程的布局,所以是看不到堆和栈的. 文件布局在内存中的映射 高地址内存 File header 栈 .text 堆 .data .bss .data .bss .text 未映射区域 a.out a.out进程的地址空间 当

剖析程序的内存布局

原文标题:Anatomy of a Program in Memory 原文地址:http://duartes.org/gustavo/blog/ [注:本人水平有限,只好挑一些国外高手的精彩文章翻译一下.一来自己复习,二来与大家分享.] 内存管理模块是操作系统的心脏:它对应用程序和系统管理非常重要.今后的几篇文章中,我将着眼于实际的内存问题,但也不避讳其中的技术内幕.由于不少概念是通用的,所以文中大部分例子取自32位x86平台的Linux和Windows系统.本系列第一篇文章讲述应用程序的内存

程序的内存布局——函数调用栈的那点事

[注]此文是<程序员的自我修养>的读书总结,其中掺杂着一些个人的理解,若有不对,欢迎拍砖. 程序的内存布局 现代的应用程序都运行在一个虚拟内存空间里,在32位的系统里,这个内存空间拥有4GB的寻址能力.现代的应用程序可以直接使用32位的地址进行寻址,整个内存是一个统一的地址空间,用户可以使用一个32位的指针访问任意内存位置. 在进程的不同地址区间上有着不同的地位,Windows在默认情况下会将高地址的2GB空间分配给内核,而Linux默认将高地址的1GB空间分配给内核,具体的内存布局如下图: