C/C++編程筆記:如何理解C語言中的嵌套函數(shù),零基礎(chǔ)也看得懂
一些程序員認(rèn)為在另一個(gè)函數(shù)內(nèi)部定義一個(gè)函數(shù)稱為“嵌套函數(shù)”。但是現(xiàn)實(shí)是它不是嵌套函數(shù),它被視為詞匯作用域。在C語言中,詞法作用域無效,因?yàn)榫幾g器無法達(dá)到/找到內(nèi)部函數(shù)的正確內(nèi)存位置。

C不支持嵌套函數(shù),因?yàn)槲覀儫o法在C中的另一個(gè)函數(shù)內(nèi)定義一個(gè)函數(shù)。我們可以在一個(gè)函數(shù)內(nèi)聲明一個(gè)函數(shù),但它不是嵌套函數(shù)。
由于嵌套函數(shù)定義無法訪問周圍塊的局部變量,因此它們只能訪問包含模塊的全局變量。這樣做是為了不必在目錄中查找全局變量。與C中一樣,有兩個(gè)嵌套作用域:本地和全局(除此之外,內(nèi)置函數(shù))。因此,嵌套函數(shù)只有有限的用途。如果嘗試在C中使用嵌套函數(shù),則將得到編譯時(shí)錯(cuò)誤。

輸出:
編譯時(shí)錯(cuò)誤:未定義對“視圖”的引用
GNU C編譯器的擴(kuò)展允許聲明嵌套函數(shù)。在GCC擴(kuò)展名下的嵌套函數(shù)的聲明需要以auto關(guān)鍵字為前綴/開頭。

另外,GCC主要通過Trampoline實(shí)現(xiàn)函數(shù)嵌套功能,那么什么是Trampoline呢?
Trampoline其實(shí)就是一段存在于棧上的可執(zhí)行代碼,它由運(yùn)行時(shí)動(dòng)態(tài)生成,通過運(yùn)行棧上的這段代碼跳轉(zhuǎn)到真正的目的代碼處。
至于函數(shù)嵌套為何要通過Trampoline去實(shí)現(xiàn),這還得從嵌套函數(shù)的特點(diǎn)說起,因?yàn)樗軌蛟L問容器函數(shù)中的局部變量:

其中offset就是容器函數(shù)中的變量,可以在嵌套函數(shù)中直接引用,這看起來似乎不難實(shí)現(xiàn):通過sp+offset即可輕松訪問容器函數(shù)的棧變量,但還有一種情況必須要考慮,那就是嵌套函數(shù)不僅僅可以在容器函數(shù)中直接調(diào)用,還可能通過函數(shù)指針在其他函數(shù)中間接調(diào)用,這時(shí)活動(dòng)棧幀布局跟容器函數(shù)就不一樣了,通過sp+offset訪問到的不再是容器函數(shù)中的對應(yīng)變量位置了,這樣就會得到意想不到的結(jié)果。
Trampoline可以有效的避免這種情況,因?yàn)門rampoline存在于容器函數(shù)的棧上,相對于要訪問的容器函數(shù)的變量相對位置是固定的,所以不管怎么調(diào)用嵌套函數(shù),執(zhí)行的都是棧上的Trampoline,這樣訪問到的容器函數(shù)的變量位置總是正確的。不過這要求在嵌套函數(shù)調(diào)用時(shí)容器函數(shù)不能退出,否則棧上的Trampoline可能會被覆蓋,同樣會得到意想不到的結(jié)果。
而且如果嵌套函數(shù)中不引用容器函數(shù)中的任何變量,那么嵌套函數(shù)會被提升為普通函數(shù),通過上面原理的分析,這點(diǎn)應(yīng)該很好理解。
另外如果你想更好的提升你的編程能力,學(xué)好C語言C++編程!彎道超車,快人一步!

UP在主頁上傳了一些學(xué)習(xí)C/C++編程的視頻教程,有興趣或者正在學(xué)習(xí)的小伙伴一定要去看一看哦!會對你有幫助的~
分享(源碼、項(xiàng)目實(shí)戰(zhàn)視頻、項(xiàng)目筆記,基礎(chǔ)入門教程)
歡迎轉(zhuǎn)行和學(xué)習(xí)編程的伙伴,利用更多的資料學(xué)習(xí)成長比自己琢磨更快哦!
編程學(xué)習(xí)書籍分享:

編程學(xué)習(xí)視頻分享:
