自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

聊聊C語(yǔ)言的內(nèi)存分配

開發(fā) 后端
在標(biāo)準(zhǔn)C語(yǔ)言中,編譯出來(lái)的可執(zhí)行程序分為代碼區(qū)(text)、數(shù)據(jù)區(qū)(data)和未初始化數(shù)據(jù)區(qū)(bss)3個(gè)部分。

[[440714]]

1.ANSI C

在ANSI C中數(shù)據(jù)類型包括:整形,浮點(diǎn)型,指針和聚合型(如數(shù)組和結(jié)構(gòu)等)

整形:

字符,短整型,整型和長(zhǎng)整型,他們都分別有有符號(hào)(singed)和無(wú)符號(hào)(unsingned)

取值范圍:

沒有帶signed或者unsigned,默認(rèn)signed

長(zhǎng)整型至少應(yīng)該和整型一樣長(zhǎng),而整型至少應(yīng)該和短整型一樣長(zhǎng)

在32位環(huán)境中,各種數(shù)據(jù)類型的長(zhǎng)度一般如下:

2ARM C

具體我們以IAR為編譯器,版本7.2

注意:

在32位ARM中,字是32位,半字是16位,字節(jié)是8位

可以看到以下關(guān)于整型的數(shù)據(jù)類型

下面使用typedef重新定義數(shù)據(jù)類型,沒有使用到long,因?yàn)槎际?2位的有一個(gè)int就夠了

  1. typedef unsigned  char       uint8;    //!< 無(wú)符號(hào)8位整型變量  
  2. typedef signed    char       int8;     //!< 有符號(hào)8位整型變量   
  3. typedef unsigned  short      uint16;   //!<無(wú)符號(hào)16位整型變量  
  4. typedef signed    short      int16;    //!< 有符號(hào)16位整型變量  
  5. typedef unsigned  int        uint32;   //!< 無(wú)符號(hào)32位整型變量  
  6. typedef signed    int        int32;    //!<有符號(hào)32位整型變量  
  7. typedef float                fp32;     //!< 單精度浮點(diǎn)數(shù)(32位長(zhǎng)度)  
  8. typedef double               fp64;     //!< 雙精度浮點(diǎn)數(shù)(64位長(zhǎng)度) 

3C語(yǔ)言內(nèi)存分配方法

在標(biāo)準(zhǔn)C語(yǔ)言中,編譯出來(lái)的可執(zhí)行程序分為代碼區(qū)(text)、數(shù)據(jù)區(qū)(data)和未初始化數(shù)據(jù)區(qū)(bss)3個(gè)部分。如下代碼

  1. #include <stdlib.h> 
  2. int a = 0;    //a在全局已初始化數(shù)據(jù)區(qū)  
  3. char *p1;    //p1在BSS區(qū)(未初始化全局變量)  
  4. void main()  
  5.     int b; //b在棧區(qū) 
  6.     int c; //C為全局(靜態(tài))數(shù)據(jù),存在于已初始化數(shù)據(jù)區(qū) 
  7.     char s[] = "abc"; //s為數(shù)組變量,存儲(chǔ)在棧區(qū), 
  8.     char *p2,*p3;  //p2、p3在棧區(qū) 
  9.     p2 = (char *)malloc(10);//分配得來(lái)的10個(gè)字節(jié)的區(qū)域在堆區(qū) 
  10.     p3 = (char *)malloc(20);//分配得來(lái)的20個(gè)字節(jié)的區(qū)域在堆區(qū) 
  11.     free(p2); 
  12.     free(p3); 

使用linux編譯之后得到的可執(zhí)行文件如下

可以看到代碼區(qū)(text)、數(shù)據(jù)區(qū)(data)和未初始化數(shù)據(jù)區(qū)(bss)。

代碼段(text):存放代碼的地方。只能訪問(wèn),不能修改,代碼段就是程序中的可執(zhí)行部分,直觀理解代碼段就是函數(shù)堆疊組成的。

數(shù)據(jù)段(data):全局變量和靜態(tài)局部變量存放的地方。也被稱為數(shù)據(jù)區(qū)、靜態(tài)數(shù)據(jù)區(qū)、靜態(tài)區(qū):數(shù)據(jù)段就是程序中的數(shù)據(jù),直觀理解就是C語(yǔ)言程序中的全局變量。注意是全局變量或靜態(tài)局部變量,局部變量不算。

未初始化數(shù)據(jù)區(qū)(bss):bss段的特點(diǎn)就是被初始化為0,bss段本質(zhì)上也是屬于數(shù)據(jù)段。

那么問(wèn)題來(lái)了,為什么要區(qū)分data段和bss段呢?

以下面代碼為例,a.c和b.c的差異只是有沒有給arr數(shù)組賦值。

可以看到a.out的bss段大,b.out的data段大。但是b.out的文件大小明顯比a.out的大很多。

那么就可以簡(jiǎn)單理解為,data段會(huì)增大可執(zhí)行文件的大小,而bss段不會(huì)。

這里我說(shuō)下自己的理解,我并沒有找到資料驗(yàn)證:

data段是全局變量,但是需要初始化值,上面我的例子是全部初始全部為1,但也可能是1024*1024個(gè)不同的數(shù)據(jù),而這些數(shù)據(jù)需要保存起來(lái),表現(xiàn)出來(lái)也就是需要保存在可執(zhí)行文件中。

bss段也是全局變量,但不需要初始化值,只需要保存一下這個(gè)全部變量的保存的數(shù)據(jù)類型和大小即可。即使它的數(shù)組容量是1024*1024,也不會(huì)占用很多可執(zhí)行文件的大小。

這里再說(shuō)明一個(gè)問(wèn)題:如果一個(gè)全部變量初始化為0,那么它也是bss段,不是data段,即使你代碼中把它初始化為0了。這點(diǎn)大家可以自行驗(yàn)證。

關(guān)于數(shù)據(jù)段,也就是data段,也會(huì)分為RO data(只讀數(shù)據(jù)段)和RW data(讀寫數(shù)據(jù)段)。

從字面意思就可以區(qū)分他們的意思,不同的是:

只讀數(shù)據(jù)段:程序使用的一些不會(huì)被更改的數(shù)據(jù),使用這些數(shù)據(jù)的方式類似查表式的操作,由于這些變量不需要更改,因此只需要放置在只讀存儲(chǔ)器中即可。

讀寫數(shù)據(jù)段:程序中是可以被更改的數(shù)據(jù),且初始化過(guò)的,所以需要防止在RAM中,且初始化的內(nèi)容放在存儲(chǔ)器中(表現(xiàn)為放入可執(zhí)行文件中)。

這樣又可以分區(qū)只讀區(qū)和讀寫區(qū)域,如下所所示(當(dāng)然bss段和下文的堆棧也是讀寫區(qū))

上面說(shuō)到“編譯出來(lái)的可執(zhí)行程序分為代碼區(qū)(text)、數(shù)據(jù)區(qū)(data)和未初始化數(shù)據(jù)區(qū)(bss)3個(gè)部分”,那運(yùn)行中就會(huì)多出來(lái)一些區(qū)域,這就是我們茶說(shuō)的堆棧,注意堆棧是兩個(gè)區(qū)域堆和棧。

棧:局部變量、函數(shù)一般在棧空間中。運(yùn)行時(shí)自動(dòng)分配&自動(dòng)回收:棧是自動(dòng)管理的,程序員不需要手工干預(yù)。方便簡(jiǎn)單。是提前分配好的連續(xù)的地址空間。棧的增長(zhǎng)方向是向下的,即向著內(nèi)存地址減小的方向。

堆:堆內(nèi)存管理者總量很大的操作系統(tǒng)內(nèi)存塊,各進(jìn)程可以按需申請(qǐng)使用,使用完釋放。程序手動(dòng)申請(qǐng)&釋放:手工意思是需要寫代碼去申請(qǐng)malloc和釋放free。可以是不連續(xù)的地址空間。堆的增長(zhǎng)方向是向上的,即向著內(nèi)存地址增加的方向。

下面是簡(jiǎn)單的演示代碼

  1. #include <stdlib.h> 
  2. #include <stdio.h> 
  3.  
  4. int bss_var;                                //未初始化全局?jǐn)?shù)據(jù)存儲(chǔ)在BSS區(qū) 
  5. int data_var=42;                            //初始化全局?jǐn)?shù)據(jù)存儲(chǔ)在數(shù)據(jù)區(qū) 
  6.  
  7. int main(int argc,char *argv[]) 
  8.   char *p ,*b; 
  9.   printf("Adr bss_var:0x%x\n",&bss_var); 
  10.   printf("Adr data_var:0x%x\n",&data_var); 
  11.   printf("the %s is at adr:0x%x\n","main",&main); 
  12.   p=(char *)alloca(32);              //從棧中分配空間 
  13.   if(p!=NULL
  14.   { 
  15.     printf("the p start is at adr:0x%x\n",p); 
  16.     printf("the p end is at adr:0x%x\n",p+31); 
  17.   } 
  18.   b=(char *)malloc(32*sizeof(char));   //從堆中分配空間 
  19.   if(b!=NULL
  20.   { 
  21.     printf("the b start is at adr:0x%x\n",b); 
  22.     printf("the b end is at adr:0x%x\n",b+31); 
  23.   } 
  24.   free(b);         //釋放申請(qǐng)的空間,以避免內(nèi)存泄漏 
  25.   while(1); 

運(yùn)行結(jié)果如下

內(nèi)存分配示意圖如下

 

責(zé)任編輯:武曉燕 來(lái)源: 知曉編程
相關(guān)推薦

2022-01-13 10:30:21

C語(yǔ)言內(nèi)存動(dòng)態(tài)

2022-11-30 08:19:15

內(nèi)存分配Go逃逸分析

2021-12-22 06:56:07

STM32C語(yǔ)言內(nèi)存

2022-01-07 13:50:55

語(yǔ)言內(nèi)存代碼

2011-07-15 01:10:13

C++內(nèi)存分配

2021-01-06 09:47:51

內(nèi)存Go語(yǔ)言

2010-02-04 14:58:06

C++內(nèi)存分配

2015-07-08 10:51:27

Objective-CRuntime

2022-02-11 09:31:23

IPV4IP地址IANA

2021-02-28 13:22:54

Java內(nèi)存代碼

2022-12-12 08:42:06

Java對(duì)象棧內(nèi)存

2020-03-11 13:44:20

編程語(yǔ)言PythonJava

2020-10-19 09:34:04

C語(yǔ)言內(nèi)存錯(cuò)誤編程語(yǔ)言

2021-08-10 19:15:17

語(yǔ)言編程應(yīng)用

2013-08-05 15:44:36

C語(yǔ)言基礎(chǔ)

2018-02-08 14:57:22

對(duì)象內(nèi)存分配

2010-09-25 15:40:52

配置JVM內(nèi)存

2021-08-16 06:56:21

Slice數(shù)組類型內(nèi)存

2021-01-07 07:53:10

JavaScript內(nèi)存管理

2022-11-02 07:23:06

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)