0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C語言和其他高級語言的區(qū)別

5RJg_mcuworld ? 來源:未知 ? 作者:李倩 ? 2018-07-17 18:05 ? 次閱讀

提到C語言,我們知道C語言和其他高級語言的最大的區(qū)別就是C語言是要操作內(nèi)存的!

我們需要知道——變量,其實(shí)是內(nèi)存地址的一個(gè)抽像名字罷了。在靜態(tài)編譯的程序中,所有的變量名都會在編譯時(shí)被轉(zhuǎn)成內(nèi)存地址。機(jī)器是不知道我們?nèi)〉拿值?,只知道地址?/p>

內(nèi)存的使用是程序設(shè)計(jì)中需要考慮的重要因素之一,這不僅由于系統(tǒng)內(nèi)存是有限的(尤其在嵌入式系統(tǒng)中),而且內(nèi)存分配也會直接影響到程序的效率。因此,我們要對C語言中的內(nèi)存管理,有個(gè)系統(tǒng)的了解。

在C語言中,定義了4個(gè)內(nèi)存區(qū)間:代碼區(qū);全局變量和靜態(tài)變量區(qū);局部變量區(qū)即棧區(qū);動態(tài)存儲區(qū),即堆區(qū);具體如下:

1、棧區(qū)(stack)— 由編譯器自動分配釋放 ,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。

2、堆區(qū)(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時(shí)可能由OS回收 。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表,呵呵。

3、全局區(qū)(靜態(tài)區(qū))(static)—全局變量和靜態(tài)變量的存儲是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的 另一塊區(qū)域。 - 程序結(jié)束后由系統(tǒng)釋放。

4、常量區(qū) —常量字符串就是放在這里的。 程序結(jié)束后由系統(tǒng)釋放

5、程序代碼區(qū)—存放函數(shù)體的二進(jìn)制代碼。

我們來看張圖:

首先我們要知道,源代碼編譯成程序,程序是放在硬盤上的,而非內(nèi)存里!只有執(zhí)行時(shí)才會被調(diào)用到內(nèi)存中!

我們來看看程序結(jié)構(gòu),ELF是是Linux的主要可執(zhí)行文件格式。ELF文件由4部分組成,分別是ELF頭(ELF header)、程序頭表(Program header table)、節(jié)(Section)和節(jié)頭表(Section header table)。具體如下:

1、Program header描述的是一個(gè)段在文件中的位置、大小以及它被放進(jìn)內(nèi)存后所在的位置和大小。即要加載的信息

2、Sections保存著object 文件的信息,從連接角度看:包括指令,數(shù)據(jù),符號表,重定位信息等等。在圖中,我們可以看到Sections中包括:

(1) .text 文本結(jié) 存放指令;

(2) .rodata 數(shù)據(jù)結(jié) readonly;

(3).data 數(shù)據(jù)結(jié)可讀可寫;

3、Section頭表(section header table)包含了描述文件sections的信息。每個(gè)section在這個(gè)表中有一個(gè)入口;每個(gè)入口給出了該section的名字,大小,等等信息。相當(dāng)于 索引

而程序被加載到內(nèi)存里面,又是如何分布的呢?我們看看上圖中:

1、正文和初始化的數(shù)據(jù)和未初始化的數(shù)據(jù)就是我們所說的數(shù)據(jù)段,正文即代碼段;

2、正文段上面是常量區(qū),常量區(qū)上面是全局變量和靜態(tài)變量區(qū),二者占據(jù)的就是初始化的數(shù)據(jù)和未初始化的數(shù)據(jù)那部分;

3、再上面就是堆,動態(tài)存儲區(qū),這里是上增長;

4、堆上面是棧,存放的是局部變量,就是局部變量所在代碼塊執(zhí)行完畢后,這塊內(nèi)存會被釋放,這里棧區(qū)是下增長;

5、命令行參數(shù)就是$0 $1之類的,環(huán)境變量什么的前面的文章已經(jīng)講過,有興趣的可以去看看。

我們知道,內(nèi)存分為動態(tài)內(nèi)存和靜態(tài)內(nèi)存,我們先講靜態(tài)內(nèi)存。

一、靜態(tài)內(nèi)存

內(nèi)存管理---存儲模型

存儲模型決定了一個(gè)變量的內(nèi)存分配方式和訪問特性,在C語言中主要有三個(gè)維度來決定:1、存儲時(shí)期 2、作用域 3、鏈接

1、存儲時(shí)期

存儲時(shí)期:變量在內(nèi)存中的保留時(shí)間(生命周期)

存儲時(shí)期分為兩種情況,關(guān)鍵是看變量在程序執(zhí)行過程中會不會被系統(tǒng)自動回收掉。

1) 靜態(tài)存儲時(shí)期 Static

在程序執(zhí)行過程中一旦分配就不會被自動回收。

通常來說,任何不在函數(shù)級別代碼塊內(nèi)定義的變量。

無論是否在代碼塊內(nèi),只要采用static關(guān)鍵字修飾的變量。

2) 自動存儲時(shí)期 Automatic

除了靜態(tài)存儲以外的變量都是自動存儲時(shí)期的,或者說只要是在代碼塊內(nèi)定義的非static的變量,系統(tǒng)會肚臍自動非配和釋放內(nèi)存;

2、作用域

作用域:一個(gè)變量在定義該變量的自身文件中的可見性(訪問或者引用)

在C語言中,一共有3中作用域:

1) 代碼塊作用域

在代碼塊中定義的變量都具有該代碼的作用域。從這個(gè)變量定義地方開始,到這個(gè)代碼塊結(jié)束,該變量是可見的;

2) 函數(shù)原型作用域

出現(xiàn)在函數(shù)原型中的變量,都具有函數(shù)原型作用域,函數(shù)原型作用域從變量定義處一直到原型聲明的末尾。

3)文件作用域

一個(gè)在所有函數(shù)之外定義的變量具有文件作用域,具有文件作用域的變量從它的定義處到包含該定義的文件結(jié)尾處都是可見的;

3、鏈接

鏈接:一個(gè)變量在組成程序的所有文件中的可見性(訪問或者引用);

C語言中一共有三種不同的鏈接:

1) 外部鏈接

如果一個(gè)變量在組成一個(gè)程序的所有文件中的任何位置都可以被訪問,則稱該變量支持外部鏈接;

2) 內(nèi)部鏈接

如果一個(gè)變量只可以在定義其自身的文件中的任何位置被訪問,則稱該變量支持內(nèi)部鏈接。

3) 空鏈接

如果一個(gè)變量只是被定義其自身的當(dāng)前代碼塊所私有,不能被程序的其他部分所訪問,則成該變量支持空鏈接

我們來看一個(gè)代碼示例:

[cpp]view plaincopy

1.#include

2.

3.inta=0;//全局初始化區(qū)

4.char*p1;//全局未初始化區(qū)

5.

6.intmain()

7.{

8.intb;//b在棧區(qū)

9.chars[]="abc";//棧

10.char*p2;//p2在棧區(qū)

11.

12.char*p3="123456";//123456\0在常量區(qū),p3在棧上。

13.staticintc=0;//全局(靜態(tài))初始化區(qū)

14.

15.p1=(char*)malloc(10);

16.p2=(char*)malloc(20);//分配得來得10和20字節(jié)的區(qū)域就在堆區(qū)。

17.

18.strcpy(p1,"123456");//123456\0放在常量區(qū),編譯器可能會將它與p3所指向的"123456"優(yōu)化成一個(gè)地方。

19.}

二、動態(tài)內(nèi)存

當(dāng)程序運(yùn)行到需要一個(gè)動態(tài)分配的變量時(shí),必須向系統(tǒng)申請取得堆中的一塊所需大小的存儲空間,用于存儲該變量。當(dāng)不在使用該變量時(shí),也就是它的生命結(jié)束時(shí),要顯示釋放它所占用的存儲空間,這樣系統(tǒng)就能對該空間進(jìn)行再次分配,做到重復(fù)使用有線的資源。下面介紹動態(tài)內(nèi)存申請和釋放的函數(shù)。

1.1 malloc 函數(shù)

malloc函數(shù)原型:

[cpp]view plaincopy

1.#include

2.

3.void*malloc(size_tsize);

size是需要動態(tài)申請的內(nèi)存的字節(jié)數(shù)。若申請成功,函數(shù)返回申請到的內(nèi)存的起始地址,若申請失敗,返回NULL。我們看下面這個(gè)例子:

[cpp]view plaincopy

1.int*get_memory(intn)

2.{

3.int*p;

4.p=(int*)malloc(sizeof(int));

5.if(p==NULL)

6.{

7.printf("mallocerror\n");

8.returnp;

9.}

10.

11.memset(p,0,n*sizeof(int));

12.}

使用該函數(shù)時(shí),有下面幾點(diǎn)要注意:

1)只關(guān)心申請內(nèi)存的大??;

2)申請的是一塊連續(xù)的內(nèi)存。記得一定要寫出錯(cuò)判斷;3)顯示初始化。即我們不知這塊內(nèi)存中有什么東西,要對其清零;

1.2 free函數(shù)

在堆上分配的額內(nèi)存,需要用free函數(shù)顯示釋放,函數(shù)原型如下:

[cpp]view plaincopy

#include

voidfree(void*ptr);

使用free(),也有下面幾點(diǎn)要注意:

1)必須提供內(nèi)存的起始地址;

調(diào)用該函數(shù)時(shí),必須提供內(nèi)存的起始地址,不能夠提供部分地址,釋放內(nèi)存中的一部分是不允許的。

2)malloc和free配對使用;

編譯器不負(fù)責(zé)動態(tài)內(nèi)存的釋放,需要程序員顯示釋放。因此,malloc與free是配對使用的,避免內(nèi)存泄漏。

[cpp]view plaincopy

free(p);

p=NULL;

p = NULL是必須的,因?yàn)殡m然這塊內(nèi)存被釋放了,但是p仍指向這塊內(nèi)存,避免下次對p的誤操作;

3)不允許重復(fù)釋放

因?yàn)檫@塊內(nèi)存被釋放后,可能已另分配,這塊區(qū)域被別人占用,如果再次釋放,會造成數(shù)據(jù)丟失;

2、我們經(jīng)常將堆和棧相比較:

2.1申請方式

stack:由系統(tǒng)自動分配。 例如,聲明在函數(shù)中一個(gè)局部變量 int b; 系統(tǒng)自動在棧中為b開辟空間

heap:需要程序員自己申請,并指明大小,在c中malloc函數(shù) ,如p1 = (char *)malloc(10);2.2 申請后系統(tǒng)的響應(yīng)

棧:只要棧的剩余空間大于所申請空間,系統(tǒng)將為程序提供內(nèi)存,否則將報(bào)異常提示棧溢出。

堆:首先應(yīng)該知道操作系統(tǒng)有一個(gè)記錄空閑內(nèi)存地址的鏈表,當(dāng)系統(tǒng)收到程序的申請時(shí),會遍歷該鏈表,尋找第一個(gè)空間大于所申請空間的堆結(jié)點(diǎn),然后將該結(jié)點(diǎn)從空閑結(jié)點(diǎn)鏈表中刪除,并將該結(jié)點(diǎn)的空間分配給程序,另外,對于大多數(shù)系統(tǒng),會在這塊內(nèi)存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內(nèi)存空間。另外,由于找到的堆結(jié)點(diǎn)的大小不一定正好等于申請的大小,系統(tǒng)會自動的將多余的那部分重新放入空閑鏈表中。

2.3申請大小的限制

棧:棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,棧的大小是2M(也有的說是1M,總之是一個(gè)編譯時(shí)就確定的常數(shù)),如果申請的空間超過棧的剩余空間時(shí),將提示overflow。因此,能從棧獲得的空間較小。

堆:堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來存儲的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見,堆獲得的空間比較靈活,也比較大。

2.4申請效率的比較:

棧由系統(tǒng)自動分配,速度較快。但程序員是無法控制的。

堆是由new分配的內(nèi)存,一般速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過用起來最方便。

2.5堆和棧中的存儲內(nèi)容

棧:在函數(shù)調(diào)用時(shí),第一個(gè)進(jìn)棧的是主函數(shù)中后的下一條指令(函數(shù)調(diào)用語句的下一條可執(zhí)行語句)的地址,然后是函數(shù)的各個(gè)參數(shù),在大多數(shù)的C編譯器中,參數(shù)是由右往左入棧的,然后是函數(shù)中的局部變量。注意靜態(tài)變量是不入棧的。 當(dāng)本次函數(shù)調(diào)用結(jié)束后,局部變量先出棧,然后是參數(shù),最后棧頂指針指向最開始存的地址,也就是主函數(shù)中的下一條指令,程序由該點(diǎn)繼續(xù)運(yùn)行。

堆:一般是在堆的頭部用一個(gè)字節(jié)存放堆的大小。堆中的具體內(nèi)容由程序員安排。

2.6存取效率的比較

char s1[] = "aaaaaaaaaaaaaaa";char *s2 = "bbbbbbbbbbbbbbbbb";aaaaaaaaaaa是在運(yùn)行時(shí)刻賦值的;而bbbbbbbbbbb是在編譯時(shí)就確定的;但是,在以后的存取中,在棧上的數(shù)組比指針?biāo)赶虻淖址?例如堆)快。

比如:

[cpp]view plaincopy

1.#include

2.voidmain()

3.{

4.chara=1;

5.charc[]="1234567890";

6.char*p="1234567890";

7.a=c[1];

8.a=p[1];

9.return;

10.}

對應(yīng)的匯編代碼

[cpp]view plaincopy

1.0:a=c[1];

2.004010678A4DF1movcl,byteptr[ebp-0Fh]

3.0040106A884DFCmovbyteptr[ebp-4],cl

4.11:a=p[1];

5.0040106D8B55ECmovedx,dwordptr[ebp-14h]

6.004010708A4201moval,byteptr[edx+1]

7.004010738845FCmovbyteptr[ebp-4],al

第一種在讀取時(shí)直接就把字符串中的元素讀到寄存器cl中,而第二種則要先把指針值讀到edx中,再根據(jù)edx讀取字符,顯然慢了。

總結(jié)

堆和棧的區(qū)別可以用如下的比喻來看出: 棧就象我們?nèi)ワ堭^里吃飯,只管點(diǎn)菜(發(fā)出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準(zhǔn)備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。

堆就象是自己動手做喜歡吃的菜肴,比較麻煩,但是比較符合自己的口味,而且自由度大。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 二進(jìn)制
    +關(guān)注

    關(guān)注

    2

    文章

    772

    瀏覽量

    41542
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7581

    瀏覽量

    135656

原文標(biāo)題:C語言和其他高級語言的最大的區(qū)別是什么?

文章出處:【微信號:mcuworld,微信公眾號:嵌入式資訊精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    C語言和其他高級語言區(qū)別

    我們需要知道——變量,其實(shí)是內(nèi)存地址的一個(gè)抽像名字罷了。在靜態(tài)編譯的程序中,所有的變量名都會在編譯時(shí)被轉(zhuǎn)成內(nèi)存地址。機(jī)器是不知道我們?nèi)〉拿值模恢赖刂贰?/div>
    發(fā)表于 10-09 10:02 ?1073次閱讀

    C語言和其他高級語言的最大的區(qū)別是什么?

    本帖最后由 24不可說 于 2018-7-16 13:50 編輯 提到C語言,我們知道C語言和其他
    發(fā)表于 07-16 13:41

    MCS的C語言和標(biāo)準(zhǔn)C語言區(qū)別

    MCS的C語言和標(biāo)準(zhǔn)C語言區(qū)別MC9S12的C語言
    發(fā)表于 07-20 07:06

    C語言和匯編語言混合編程方法和C語言中斷處理方法

    C語言和匯編語言混合編程方法和C語言中斷處理方法,new
    發(fā)表于 01-06 14:36 ?36次下載

    vhdl語言和c語言區(qū)別大嗎?差異性體現(xiàn)在哪兒

    相信對vhdl語言和c語言區(qū)別也有了一定的了解,并且它們兩者之間的區(qū)別還是挺大的,下面我們詳細(xì)細(xì)數(shù)一下它們的
    發(fā)表于 11-09 16:06 ?2w次閱讀
    vhdl<b class='flag-5'>語言和</b><b class='flag-5'>c</b><b class='flag-5'>語言</b><b class='flag-5'>區(qū)別</b>大嗎?差異性體現(xiàn)在哪兒

    r語言和matlab有什么區(qū)別

    做數(shù)據(jù)分析、科學(xué)計(jì)算等離不開工具、語言的使用,目前最流行的數(shù)據(jù)語言,無非是MATLAB,R語言,Python這三種語言。下面我將分析r語言和
    發(fā)表于 01-05 15:56 ?4.6w次閱讀

    高級語言和匯編語言_機(jī)器語言區(qū)別

    本文首先介紹了高級語言的優(yōu)缺點(diǎn)、匯編語言的優(yōu)缺點(diǎn)及使用匯編語言的理由,其次介紹了機(jī)器語言的優(yōu)缺點(diǎn),最后闡述了
    的頭像 發(fā)表于 04-16 10:28 ?3w次閱讀

    詳談C語言和C++的區(qū)別和聯(lián)系

    在學(xué)習(xí)了C語言和C++之后,這兩者之間的區(qū)別我們需要仔細(xì)的捋一捋!
    的頭像 發(fā)表于 06-29 14:56 ?5655次閱讀
    詳談<b class='flag-5'>C</b><b class='flag-5'>語言和</b><b class='flag-5'>C</b>++的<b class='flag-5'>區(qū)別</b>和聯(lián)系

    單片機(jī)C語言和C語言為什么有差異?

    許多小伙伴在學(xué)完C語言后想入門單片機(jī),但學(xué)著學(xué)著發(fā)現(xiàn)明明都是C語言,為什么單片機(jī)C語言和我當(dāng)初學(xué)
    發(fā)表于 09-01 16:39 ?3716次閱讀

    單片機(jī)匯編語言和c語言區(qū)別是什么

    單片機(jī)從誕生到現(xiàn)在,經(jīng)過了將近70年的發(fā)展。眾所周知,單片機(jī)是可以通過編寫程序?qū)崿F(xiàn)產(chǎn)品的功能,這么多年來,單片機(jī)的規(guī)格并沒有多大變化,而單片機(jī)編程一般使用的都是匯編語言和c語言。那么,單片機(jī)匯編
    發(fā)表于 06-21 16:59 ?6328次閱讀

    腳本語言和編程語言區(qū)別

    腳本語言和編程語言是計(jì)算機(jī)語言的兩個(gè)主要分類。盡管兩者都是用于編寫計(jì)算機(jī)程序的工具,但它們在設(shè)計(jì)和運(yùn)行方式上存在一些顯著的區(qū)別。下面將詳細(xì)探討腳本
    的頭像 發(fā)表于 11-22 14:33 ?2776次閱讀

    如何選擇創(chuàng)建c語言和c++

    選擇創(chuàng)建 C 語言和 C++ 都需要綜合考慮多個(gè)因素。在決定使用哪種語言之前,我們需要對這兩種語言的特點(diǎn)、優(yōu)缺點(diǎn)、適用場景、學(xué)習(xí)成本等進(jìn)行全
    的頭像 發(fā)表于 11-27 15:58 ?534次閱讀

    vb語言和c++語言區(qū)別

    VB語言和C++語言是兩種不同的編程語言,雖然它們都屬于高級編程語言,但在設(shè)計(jì)和用途上有很多
    的頭像 發(fā)表于 02-01 10:20 ?1828次閱讀

    plc編程語言c語言的聯(lián)系 c語言和PLC有什么區(qū)別

    語言,主要用于開發(fā)各種應(yīng)用程序。盡管PLC編程語言和C語言有一些相似之處,但它們之間也存在一些明顯的區(qū)別。 首先,PLC編程
    的頭像 發(fā)表于 02-05 14:21 ?3599次閱讀

    PLC編程語言和C語言區(qū)別

    在工業(yè)自動化和計(jì)算機(jī)編程領(lǐng)域中,PLC(可編程邏輯控制器)編程語言和C語言各自扮演著重要的角色。盡管兩者都是編程語言,但它們在多個(gè)方面存在顯著的區(qū)別
    的頭像 發(fā)表于 06-14 17:11 ?2121次閱讀