通常我們都是學(xué)了標(biāo)準(zhǔn)c語言教程后從事單片機(jī)c語言的編寫的, 那就先要明白一點(diǎn), 標(biāo)準(zhǔn)c語言實(shí)際上是起源于pc平臺(tái)上的一種語言, 標(biāo)準(zhǔn)c語言肯定是不會(huì)照顧到單片機(jī)的特殊性的. 因此單片機(jī)c編譯器中的c語言是一種基于標(biāo)準(zhǔn)c,但是又有相應(yīng)修改擴(kuò)充的擴(kuò)展c語言.所以在單片機(jī)c編譯器里寫程序時(shí)一定要了解單片機(jī)編譯器擴(kuò)展c語言的不同之處, 絕不能死板地照搬標(biāo)準(zhǔn)c.在標(biāo)準(zhǔn)c里, 局部變量是函數(shù)在調(diào)用的時(shí)候才臨時(shí)分配存儲(chǔ)空間的,全局變量是程序整個(gè)生命周期都一直存在的.不過要知道,臨時(shí)分配存儲(chǔ)空間是需要操作系統(tǒng)內(nèi)存管理程序支持的, 單片機(jī)中通常都沒有操作系統(tǒng),也就不能實(shí)現(xiàn)像pc平臺(tái)中那樣的局部變量的空間分配.這里就需要深入了解一下單片機(jī)的c編譯器究竟是如何處理局部變量的,如果對(duì)此沒有概念,碰到調(diào)試過程中的一些奇異現(xiàn)象恐怕只能覺匪夷所思了.
本文引用地址:http://m.butianyuan.cn/article/201611/322315.htm另外需要知道的一點(diǎn)是, 不同的編譯器對(duì)于局部變量的處理方法也不一樣, 不能學(xué)了一個(gè)就到處照搬. 這里拿KEIL C ,IARAVR, ICCAVR這個(gè)三個(gè)編譯器做分析比較.
首先說 Keil C51 , 它的局部變量并不是在堆棧中, C51為了提高代碼的效率, 根據(jù) 51 處理器的特性. 編譯器對(duì)函數(shù)局部變量的安排進(jìn)行了處理.局部變量如果不能分配到 寄存器里, 就放在 RAM 中了.編譯器通過覆蓋分析, 可以共享局部變量的地址空間.。最終的DATA使用量取決于調(diào)用鏈中那個(gè)使用DATA最多的鏈。所以,在程序中增加一個(gè)局部變量,如果不是位于那個(gè)使用DATA最多的鏈中,需要的DATA數(shù)量是有可能不會(huì)增加的。
如:main()->f11()->f12()->f13()....//鏈1
|----->f21()->f22()->f23()....//鏈2
因?yàn)閒11(),f21()不在同一個(gè)調(diào)用鏈上,顯然,f11()中使用的局部變量,可以和f21()中的局部變量,使用同一個(gè)存儲(chǔ)單元。因?yàn)樗鼈冎械娜魏我粋€(gè)處在生命期內(nèi)的話,另一個(gè)必然已經(jīng)離開它的生命周期,同時(shí)它的局部變量也離開了它的生命周期,這些局部變量所占用的存儲(chǔ)單元當(dāng)然可以另做它用了。
假設(shè)鏈1目前的局部變量需要50個(gè)存儲(chǔ)單元,鏈2需要40個(gè)存儲(chǔ)單元。那么你在鏈2中加入不多于10個(gè)單元的局部變量的話,程序最終需要的存儲(chǔ)單元數(shù)量是不會(huì)增加的。
再說ICCAVR ,它把局部變量存放在軟件堆??臻g中.ICCAVR使用兩個(gè)堆棧:一個(gè)用于子程序調(diào)用和中斷操作的硬件堆棧,一個(gè)用于傳遞參數(shù)、臨時(shí)變量和局部變量的軟件堆棧。硬件堆棧是從數(shù)據(jù)內(nèi)存的頂部開始分配的,在硬件堆棧下面再分配一定數(shù)量的字節(jié)作為軟件堆棧。
IARAVR對(duì)于局部變量的處理方法與ICCAVR一樣. 它也有兩個(gè)堆棧,一個(gè)是data stack ,一個(gè)是return address stack.分別用于存放臨時(shí)變量,局部變量,傳遞參數(shù), 和函數(shù)返回地址.
這里需要注意的是, 局部變量存放在堆棧中的處理方式一定要保證堆棧足夠大, 特別是定義了局部數(shù)組變量的情況下,一旦數(shù)組過大,超過了堆棧大小就會(huì)發(fā)生堆棧溢出,如果只是讀取數(shù)據(jù)還好, 一旦寫入數(shù)據(jù),就會(huì)破壞堆棧空間以外的數(shù)據(jù), 導(dǎo)致程序時(shí)常.
評(píng)論