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

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

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

當(dāng)函數(shù)執(zhí)行完畢后,如何返回調(diào)用處?

AGk5_ZLG_zhiyua ? 來(lái)源:未知 ? 作者:佚名 ? 2017-09-14 14:27 ? 次閱讀

周立功教授數(shù)年之心血之作《程序設(shè)計(jì)與數(shù)據(jù)結(jié)構(gòu)》以及《面向AMetal框架與接口編程(上)》,書本內(nèi)容公開后,在電子行業(yè)掀起一片學(xué)習(xí)熱潮。經(jīng)周立功教授授權(quán),本公眾號(hào)特對(duì)《程序設(shè)計(jì)與數(shù)據(jù)結(jié)構(gòu)》一書內(nèi)容進(jìn)行連載,愿共勉之。

第二章為程序設(shè)計(jì)技術(shù),本文為2.3 棧與函數(shù)返回。

當(dāng)函數(shù)執(zhí)行完畢后,如何返回調(diào)用處呢?由于該函數(shù)可能會(huì)被多次調(diào)用,且每次調(diào)用的地方很可能不一樣,這樣被調(diào)用函數(shù)也就不可能知道自己該返回到哪里,因此在調(diào)用函數(shù)時(shí)必須告訴被調(diào)用函數(shù)應(yīng)返回到哪里?

>>> 2.3.1 堆棧

為了保存變量(數(shù)據(jù)),通常計(jì)算機(jī)會(huì)提供非常多的內(nèi)存。為了便于管理內(nèi)存,將所有變量使用的內(nèi)存稱為棧,而將未分配的內(nèi)存區(qū)域稱為堆。這些未分配的內(nèi)存區(qū)域,程序員可以塊為單位請(qǐng)求它。這部分內(nèi)存是由操作系統(tǒng)管理的,一旦一塊內(nèi)存被分配出去,它只能由分配了這塊內(nèi)存的原始代碼使用,并使用指針訪問(wèn)這塊內(nèi)存。由于內(nèi)存是稀缺資源,當(dāng)程序不再需要該內(nèi)存時(shí),都應(yīng)該釋放回去。如果不這樣做,程序?qū)?huì)耗光內(nèi)存,導(dǎo)致運(yùn)行速度下降甚至崩潰。這就是因?yàn)槌绦騿T沒(méi)有釋放本應(yīng)釋放的內(nèi)存,造成了所謂的內(nèi)存泄漏。

堆和棧是兩種常用的數(shù)據(jù)結(jié)構(gòu),主要用于數(shù)據(jù)的動(dòng)態(tài)存儲(chǔ)。當(dāng)程序執(zhí)行時(shí),棧中存儲(chǔ)的是程序的執(zhí)行過(guò)程,比如,main()函數(shù)的局部變量argc和argv都在棧中,而使用malloc()函數(shù)動(dòng)態(tài)分配的內(nèi)存是存儲(chǔ)在堆中的,堆棧共享同一塊內(nèi)存區(qū)域。通常程序棧占據(jù)這塊區(qū)域的下部,而堆用的是上部。當(dāng)調(diào)用函數(shù)時(shí),函數(shù)的棧幀被推到棧上,棧向上“長(zhǎng)出”一個(gè)棧幀。當(dāng)函數(shù)終止時(shí),其棧幀從程序棧彈出。雖然棧所使用的內(nèi)存不會(huì)被清理,但最終可能會(huì)被推到程序棧上的另一個(gè)棧幀覆蓋。動(dòng)態(tài)分配的內(nèi)存來(lái)自堆,堆向下生長(zhǎng)。隨著內(nèi)存的分配和釋放,堆中會(huì)布滿碎片。盡管堆是向下生長(zhǎng)的,但這只是大體方向,實(shí)際上內(nèi)存可能在堆上的任意位置分配。

平常大家所說(shuō)的“堆?!敝饕侵笚#?jì)算機(jī)在硬件上直接支持棧。在計(jì)算機(jī)科學(xué)中,棧是一個(gè)抽象的概念。它的抽象行為特征是棧可以存儲(chǔ)相同類型的數(shù)據(jù),通常又將棧中的數(shù)據(jù)稱為元素。只允許向棧中壓入一個(gè)元素(即入棧push),或從棧中刪除一個(gè)元素(即出棧pop),且元素按照“后進(jìn)先出”原則處理(last in,first out,LIFO),禁止測(cè)試或修改不在棧頂?shù)脑亍?/p>

圖2.7 四種棧示意圖

如圖2.7所示為通用計(jì)算機(jī)4種形式的棧,分別稱之為滿遞減堆棧、空遞減堆棧、滿遞增堆棧和空遞增堆棧,這些都是棧的物理結(jié)構(gòu)。其中的“遞減”是指數(shù)據(jù)入棧時(shí)堆棧指針的值減少,即堆棧從高地址向下增長(zhǎng),就像鐘乳石一樣?!斑f增”是指數(shù)據(jù)入棧時(shí)堆棧指針的值增加,即堆棧從低地址向上增長(zhǎng),就像石筍一樣。而“滿”是指SP指向的存儲(chǔ)單元保存最后入棧的數(shù)據(jù);“空”是指SP指向的存儲(chǔ)單元將保存下一個(gè)入棧的數(shù)據(jù)。4種形式的棧都對(duì)應(yīng)相同的邏輯數(shù)據(jù)結(jié)構(gòu),本書后續(xù)章節(jié)除非特殊說(shuō)明,否則均以“滿遞增堆棧”為例。

>>> 2.3.2 入棧與出棧

假設(shè)允許入棧和出棧數(shù)據(jù)為int,即sp為(int *)類型變量。如果入棧的數(shù)據(jù)小于sizeof(int)個(gè)字節(jié),則需要將其轉(zhuǎn)換成int類型數(shù)據(jù)才能入棧,且出棧后也要進(jìn)行相應(yīng)的類型轉(zhuǎn)換。對(duì)于入棧的數(shù)據(jù)大于sizeof(int)個(gè)字節(jié),則只能拆分?jǐn)?shù)據(jù),一次入棧數(shù)據(jù)的一部分,通過(guò)多次入棧完成整個(gè)數(shù)據(jù)的入棧;而出棧這個(gè)數(shù)據(jù)也要多次,全部出棧后再組合成原始數(shù)據(jù)。

1. 入棧(push)操作

如果將sp當(dāng)作(int *)類型的變量,則對(duì)于滿遞增堆棧來(lái)說(shuō),將數(shù)據(jù)data入棧用C語(yǔ)言描述如下(詳見(jiàn)圖2.8):

圖2.8 入棧操作示意圖

如果data的長(zhǎng)度大于sizeof(int),則需要將數(shù)據(jù)拆分后多次入棧,入棧的順序可以先低位后高位,也可以反過(guò)來(lái)。如果入棧的順序?yàn)橄鹊臀缓蟾呶唬涫纠斠?jiàn)程序清單 2.27。

程序清單 2.27 先低位后高位順序入棧示例

這里假設(shè)data可以象整數(shù)一樣移位,且sizeof(data)是sizeof(int)的4倍。

2. 出棧(pop)操作

如果將sp當(dāng)作(int *)類型的變量,則對(duì)于滿遞增堆棧來(lái)說(shuō),將數(shù)據(jù)出棧用C語(yǔ)言描述如下(假設(shè)出棧的數(shù)據(jù)保存到變量data中,詳見(jiàn)圖2.9):

圖2.9 出棧操作示意圖

如果出棧數(shù)據(jù)data的長(zhǎng)度大于sizeof(int),則需要多次出棧后拼接數(shù)據(jù),其拼接的順序?yàn)槿霔5姆葱?。如果入棧的順序?yàn)橄鹊臀缓蟾呶唬斠?jiàn)程序清單 2.28。

程序清單 2.28 先高位后低位順序出棧示例

這里假設(shè)data可以象整數(shù)一樣進(jìn)行位操作,且sizeof(data)是sizeof(int)的4倍。

>>> 2.3.3 函數(shù)的調(diào)用與返回

在討論ADT棧之前,首先看一種用于處理程序運(yùn)行時(shí)的函數(shù)調(diào)用的系統(tǒng)棧。每當(dāng)函數(shù)被調(diào)用時(shí),系統(tǒng)首先創(chuàng)建一個(gè)稱作活動(dòng)記錄或棧幀的結(jié)構(gòu),將其放在系統(tǒng)棧的棧頂。初始時(shí),被調(diào)函數(shù)的活動(dòng)記錄只包含一個(gè)指向前一個(gè)活動(dòng)記錄的指針和一個(gè)返回地址。前一個(gè)活動(dòng)記錄的指針指向調(diào)用函數(shù)的活動(dòng)記錄,而返回地址包含的是函數(shù)調(diào)用結(jié)束后下一條執(zhí)行語(yǔ)句的地址。因?yàn)樵谌魏螘r(shí)刻只有一個(gè)函數(shù)被執(zhí)行,所以被執(zhí)行的函數(shù)就是活動(dòng)記錄位于系統(tǒng)棧棧頂?shù)暮瘮?shù)。

如果該函數(shù)又調(diào)用其它函數(shù),那么函數(shù)中的局部變量(靜態(tài)局部變量除外)及其參數(shù)也將加到其活動(dòng)記錄中,然后為被調(diào)函數(shù)創(chuàng)建一個(gè)新的活動(dòng)記錄并存放在系統(tǒng)棧棧頂?shù)暮瘮?shù)。當(dāng)被調(diào)函數(shù)結(jié)束時(shí),刪除該活動(dòng)記錄。此時(shí)調(diào)用函數(shù)的活動(dòng)記錄又位于系統(tǒng)棧的棧頂,繼續(xù)運(yùn)行該函數(shù)。

C語(yǔ)言通過(guò)硬件棧保存函數(shù)的返回地址,被調(diào)用函數(shù)將返回地址出棧到程序計(jì)數(shù)器PC中,以返回到調(diào)用點(diǎn),其示例代碼詳見(jiàn)程序清單2.29。

程序清單2.29 函數(shù)的調(diào)用與返回示例

對(duì)于程序清單2.29(10)來(lái)說(shuō),用C語(yǔ)言描述如下:

對(duì)于程序清單2.29(5)來(lái)說(shuō),用C語(yǔ)言描述如下:

由此可見(jiàn),當(dāng)調(diào)用函數(shù)時(shí),將主程序代碼行的下一條指令的地址保存到棧中;當(dāng)函數(shù)返回時(shí),程序就會(huì)從棧中獲取該地址,并從那一點(diǎn)繼續(xù)向下執(zhí)行。在函數(shù)調(diào)用了其它函數(shù)的情況下,將每一個(gè)返回地址都放到棧中;當(dāng)函數(shù)結(jié)束時(shí),就可以找到它們?cè)跅V械牡刂贰?/p>

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

    關(guān)注

    0

    文章

    182

    瀏覽量

    19717

原文標(biāo)題:周立功:棧與函數(shù)返回的應(yīng)用

文章出處:【微信號(hào):ZLG_zhiyuan,微信公眾號(hào):ZLG致遠(yuǎn)電子】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    一文詳解python調(diào)用函數(shù)

    函數(shù)被定義,本身是不會(huì)自動(dòng)執(zhí)行的,只有在被調(diào)用后,函數(shù)才會(huì)被執(zhí)行,得到相應(yīng)的結(jié)果。但是在 Py
    發(fā)表于 10-01 10:45 ?619次閱讀

    如何查看及更改函數(shù)/函數(shù)塊的調(diào)用環(huán)境

    是循環(huán)執(zhí)行,當(dāng)一個(gè)功能塊被多個(gè)外部函數(shù)/函數(shù)調(diào)用時(shí),我們應(yīng)如何查看某一次調(diào)用時(shí)的內(nèi)部變量呢?這
    的頭像 發(fā)表于 11-17 09:08 ?839次閱讀
    如何查看及更改<b class='flag-5'>函數(shù)</b>/<b class='flag-5'>函數(shù)</b>塊的<b class='flag-5'>調(diào)用</b>環(huán)境

    代碼未從函數(shù)調(diào)用返回

    調(diào)用函數(shù),但是當(dāng)調(diào)用我的配置時(shí)鐘函數(shù)時(shí),它執(zhí)行函數(shù)
    發(fā)表于 09-16 07:11

    當(dāng)調(diào)用TCPIP_DHCP_IsServerDetected()函數(shù)時(shí)總是返回0

    Harmony v1.09在DHCP客戶端模式下,在設(shè)備從DHCP服務(wù)器成功獲取IP地址之后,當(dāng)調(diào)用TCPIP_DHCP_IsServerDetected()函數(shù)時(shí),它總是返回0。(傳
    發(fā)表于 04-06 14:37

    C++教程之函數(shù)的遞歸調(diào)用

    C++教程之函數(shù)的遞歸調(diào)用執(zhí)行函數(shù) f 的過(guò)程中,又要調(diào)用 f 函數(shù)本身,稱為
    發(fā)表于 05-15 18:00 ?35次下載

    高效的C編程之函數(shù)調(diào)用

    指令BL或MOV pc,lr一般只需要6個(gè)指令周期(ARM7上)。 在函數(shù)的入口和出口使用多寄存器加載/存儲(chǔ)指令LDM和STM(Thumb指令使用PUSH和POP)提高函數(shù)體的執(zhí)行效率。 ARM體系結(jié)構(gòu)過(guò)程
    發(fā)表于 10-17 16:49 ?6次下載
    高效的C編程之<b class='flag-5'>函數(shù)</b><b class='flag-5'>調(diào)用</b>

    淺談C語(yǔ)言return語(yǔ)句和main 函數(shù)返回

    函數(shù)中,如果碰到return 語(yǔ)句,那么程序就會(huì)返回調(diào)用函數(shù)的下一條語(yǔ)句執(zhí)行,也就是說(shuō)跳出函數(shù)
    發(fā)表于 05-10 10:53 ?5241次閱讀

    Python-函數(shù)的進(jìn)階與遞歸

    在程序開發(fā)中,有時(shí)候,會(huì)希望一個(gè)函數(shù)執(zhí)行結(jié)束,告訴調(diào)用者 **一個(gè)結(jié)果** ,以便調(diào)用者針對(duì)結(jié)果作后續(xù)的處理,
    的頭像 發(fā)表于 02-16 15:19 ?732次閱讀
    Python-<b class='flag-5'>函數(shù)</b>的進(jìn)階與遞歸

    return-函數(shù)返回值是什么

    return關(guān)鍵字后接變量名或表達(dá)式可以將函數(shù)的計(jì)算結(jié)果返回調(diào)用處。變量或表達(dá)式等同于接收果汁、豆?jié){的杯子。如果函數(shù)沒(méi)有返回值,retur
    的頭像 發(fā)表于 02-23 10:52 ?1134次閱讀
    return-<b class='flag-5'>函數(shù)</b>的<b class='flag-5'>返回</b>值是什么

    什么是函數(shù)返回值?

    函數(shù)返回值是函數(shù)調(diào)用后,執(zhí)行調(diào)用函數(shù)內(nèi)代碼
    的頭像 發(fā)表于 04-04 17:21 ?4745次閱讀

    python定義函數(shù)調(diào)用函數(shù)的順序

    定義函數(shù)調(diào)用函數(shù)的順序 函數(shù)被定義,本身是不會(huì)自動(dòng)執(zhí)行的,只有在被
    的頭像 發(fā)表于 10-04 17:17 ?1240次閱讀

    python函數(shù)函數(shù)之間的調(diào)用

    中沒(méi)有調(diào)用執(zhí)行y()函數(shù),只是執(zhí)行了return y。而y變量也沒(méi)有值,所以整個(gè)程序的返回值就為無(wú)結(jié)果。 3.2 第二種情況 程序代碼如下:
    的頭像 發(fā)表于 10-04 17:17 ?549次閱讀

    C語(yǔ)言函數(shù)返回1和返回0究竟哪個(gè)好?

    C語(yǔ)言函數(shù)返回1和返回0究竟哪個(gè)好? 在C語(yǔ)言中,很多函數(shù)需要返回一個(gè)值來(lái)表示函數(shù)是否成功
    的頭像 發(fā)表于 10-31 14:43 ?940次閱讀

    tuple函數(shù)怎么返回多個(gè)值

    在編程領(lǐng)域中,函數(shù)是非常重要的構(gòu)建模塊,它能夠接受輸入?yún)?shù)并執(zhí)行特定的計(jì)算,最終返回結(jié)果供程序使用。常規(guī)的函數(shù)只能返回一個(gè)值,但有時(shí)我們希望
    的頭像 發(fā)表于 11-21 16:33 ?657次閱讀

    怎么讓python執(zhí)行執(zhí)行

    在Python中,可以使用一些技術(shù)來(lái)確保程序執(zhí)行完畢執(zhí)行其他任務(wù)。下面將詳細(xì)介紹幾種方法。 一、使用阻塞方式執(zhí)行程序 阻塞方式是最簡(jiǎn)單的
    的頭像 發(fā)表于 11-29 15:09 ?3323次閱讀