久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機(jī)教程網(wǎng) >> MCU設(shè)計(jì)實(shí)例 >> 瀏覽文章

指針過界引起全局變量改變的錯(cuò)誤

作者:huqin   來源:本站原創(chuàng)   點(diǎn)擊數(shù):  更新時(shí)間:2014年11月10日   【字體:

  最近,在寫程序的時(shí)候,碰到一個(gè)在自己看來非常不可思議的問題。當(dāng)然,或者高手就覺得大驚少怪了,呵呵。

 

  以下是問題相關(guān):

  平臺(tái):MEGA64;

  編譯環(huán)境:codeVisonAVR;

  問題:一個(gè)全局變量在定義的時(shí)候直接賦值為0,但在程序運(yùn)行過程中,沒有改變該變量的操作,可是奇怪的是,程序在運(yùn)行一段時(shí)間之后,這個(gè)全局變量居然自動(dòng)改變了。

  發(fā)現(xiàn)問題之后,我很難理解,一直無法找到原因。

  一開始,我就懷疑是不是哪里的存儲(chǔ)空間溢出重疊了,但由于對各種變量的存儲(chǔ)位置,不是十分的了解,也就沒有再對此做更深層的探究;其次,我懷疑是不是哪里的指針跳錯(cuò)了,跳到全局變量那里,造成全局變量的改變,不過對于這一點(diǎn),我又自認(rèn)很仔細(xì)的檢查了程序,的確沒有發(fā)現(xiàn)指針跳錯(cuò)的地方。

  現(xiàn)在看來,其實(shí),我的兩個(gè)懷疑,都和指針有關(guān)的。

  后來,和志剛討論一下,他一開始就提出:是不是堆設(shè)置不夠。他說的堆是指hardware stack,我一開始不知道什么是hardware stack的。我猜他的意思是說,用于程序返回堆棧的空間太小了,以至于,硬件堆棧溢出,覆蓋了全局變量,自然造成全局變量的改變。

  一開始我沒有弄懂他的意思。明白之后,我覺得很有可能,不過,仔細(xì)看編譯結(jié)果,又大概可以排除這個(gè)可能了,以下是編譯結(jié)果:

Bit variables area: 2h to 2h
Bit variables size: 1 byte(s)

Data Stack area: 100h to 4FFh
Data Stack size: 1024 byte(s)
Estimated Data Stack usage: 98 byte(s)

Global variables area: 500h to 5DCh
Global variables size: 221 byte(s)

Hardware Stack area: 5DDh to 10FFh
Hardware Stack size: 2851 byte(s)

  從最后一行可知,硬件堆棧大得很,4K的SRAM,已占2.8K。一般來說,就算是函數(shù)多層嵌入也不可能占如此之大的空間,網(wǎng)上說,就算浮點(diǎn)函數(shù),40B都已經(jīng)足夠。

  不過,由于志剛的提示,讓我注意到上面的編譯結(jié)果,以前我不知道全局變量是怎樣存儲(chǔ)的,現(xiàn)在就明白了,上面倒數(shù)3、4行,就是說全局變量的。可見,全局變量是保存在數(shù)據(jù)堆棧與硬件堆棧的中間,剛才志剛說,可能硬件堆棧溢出,造成全局變量的改變。雖然在這里這個(gè)可能不大了,但是,同理,會(huì)不會(huì)是數(shù)據(jù)堆棧溢出,造成全局變量的改變呢?因?yàn)椋缮厦鎺仔芯幾g結(jié)果可知,全局變量正處于數(shù)據(jù)堆棧和硬件堆棧之間,兩者的溢出皆有可能造成全局變量的改變。不過,“Estimated Data Stack usage: 98 byte(s)”,這里又很明顯提示,估算的數(shù)據(jù)堆棧實(shí)際用到的大小只有98B,也遠(yuǎn)遠(yuǎn)小于1024B。

  所以說,不管是數(shù)據(jù)堆棧還是硬件堆棧,兩者都很難簡單的溢出。

  下面是我在codeVisionAVR的幫助文檔上面找到關(guān)于RAM的結(jié)構(gòu)圖:


 

  可知,codeVisionAVR是如何分配SRAM的(其它編譯器,各不相同的),這里簡單述說,以備以后參考。以maga64為例。(芯片資料說的4K SRAM,是不包括地址前面的100B的,也就是說SRAM的大小從數(shù)據(jù)堆棧開始數(shù)起)

  首先是,32個(gè)工作寄存器+64個(gè)I/O寄存器,這里占了RAM地址分配的前100字節(jié),0H-99H;

  其次是,數(shù)據(jù)堆棧,而且是由高往低堆的,也就是,先從地址高處往低處進(jìn)棧,由于它是用Y寄存器來做數(shù)據(jù)堆棧的指針的,所以,數(shù)據(jù)堆棧就從Y的初始值開始,到地址100H結(jié)尾,這個(gè)大小可以在編譯器工程設(shè)置里面設(shè)置,一般可以先編譯程序,看編譯估算的實(shí)際數(shù)據(jù)棧使用大小,再去定數(shù)據(jù)堆棧的大小,自然要定大一點(diǎn),防止溢出。主要用于動(dòng)態(tài)儲(chǔ)存局部變量、函數(shù)參數(shù)和中斷時(shí)各工作狀態(tài)寄存器的值;

  接著是,全局變量區(qū)域,這個(gè)是編譯器通過統(tǒng)計(jì)程序的全局變量數(shù)量而定的。用于保存全局變量;

  再接著是,硬件堆棧,以SP初始值開始,到全局變量最高地址為止,而且和數(shù)據(jù)堆棧一樣,也是由高往低堆的。用于保存函數(shù)返回地址;

  最后是,堆(heap),是malloc, calloc, realloc and free等鏈表函數(shù)用來建立鏈表的內(nèi)存空間,如果不使用這個(gè)函數(shù),必須設(shè)置為0.

  由上面可知,由于全局變量處于數(shù)據(jù)堆棧和硬件堆棧中間,而后兩者都是由高往低進(jìn)棧的,所以說,如果正常溢出,只能是硬件堆棧溢出才可以造成全局變量的改變,而數(shù)據(jù)堆棧的溢出不可能造成這個(gè)問題。可是現(xiàn)在硬件堆棧這么多,也幾乎不可能是它溢出造成這個(gè)問題的。

  那會(huì)是什么原因造成上面那個(gè)問題的呢?分析之后,我重新再仔細(xì)查找程序,最后還是找到了原因。還好,這些程序原先不是我寫的,呵呵。

  有一個(gè)以數(shù)組的地址指針為參數(shù)的函數(shù)example(char *pTemp),主函數(shù)調(diào)用它的時(shí)候,傳一個(gè)4位數(shù)組temp[4]給它,如:example(temp);

  下面大略的代碼:

  main()

  {

    char temp[4];

    example(temp);

  }

  length[]={1,2,4};

  example(char *pTemp)

  {

    cLength=length[getIndex()];

    for(i=0;i<clength;i++)

    {

      *pTemp=readvalue();

      pTemp++;

    }

  }

  由于length是一個(gè)3位數(shù)組,如果getIndex()的值大于2,就造成cLength得到的值不在{1,2,4}內(nèi),而是儲(chǔ)存length[]={1,2,4}往后地址的值,這個(gè)值是不確定的,很有可能是遠(yuǎn)遠(yuǎn)大于4。這樣就造成,for里面的循環(huán)次數(shù)遠(yuǎn)遠(yuǎn)大于4次,因?yàn)椋羔?pTemp本來指向一個(gè)4位的數(shù)組temp[4],現(xiàn)在由于pTemp++超過3次,已經(jīng)不是指向temg[]這個(gè)4位數(shù)組了,而是大于temp[4]地址的地址了。

  我們知道,這個(gè)temp[]是一個(gè)局部變量,它應(yīng)該保存在SRAM的數(shù)據(jù)堆棧里面,而數(shù)據(jù)堆棧是由高往低進(jìn)棧的,緊挨著的就是全局變量區(qū)域,這個(gè)temp必定就是保存在離全局變量區(qū)域不遠(yuǎn)的數(shù)據(jù)堆棧里面。于是,只要for的次數(shù)夠大,它不但改變了比temp后進(jìn)的數(shù)據(jù)堆棧的數(shù)據(jù),而且,跨過數(shù)據(jù)堆棧與全局變量區(qū)域的界限,直接修改了全局變量的某些值!

  其實(shí),原來寫這個(gè)程序的人,已經(jīng)做個(gè)防止getIndex()大于2的處理,可是呢,悲劇的是length[]卻少了一位數(shù)。呵呵,好在我究竟還是數(shù)了數(shù)它的位數(shù)(在實(shí)際的那個(gè)程序里,這個(gè)數(shù)組的位數(shù)自然不會(huì)是3位這么少,這樣一眼就可以看出來少不少。)。不過,如果不是志剛的提示,讓我提起心思去了解存儲(chǔ)空間的問題,即使我數(shù)出來位數(shù)少了一位,也不一定知道問題的根本原因所在!

  其實(shí),這里就是指針惹的禍。不怪人家說,指針是C、C++的靈魂啊——你知道,靈魂這東西,雖然有可能是個(gè)天使,也有可能是個(gè)惡魔。

 

關(guān)閉窗口

相關(guān)文章

主站蜘蛛池模板: 在线欧美一区二区 | 中文字幕精| 日韩一区二区在线播放 | 欧美性高潮 | 激情六月丁香婷婷 | 毛片日韩 | 国产精品视频一区二区三区不卡 | 精品欧美二区 | 国精产品一区一区三区免费完 | 亚洲第一视频 | 欧美精品一区三区 | 成人夜晚看av | 精品视频免费 | av香蕉 | 亚洲综合在线一区 | 日韩成人免费 | jav成人av免费播放 | 毛片高清 | 成人片免费看 | 国产精品久久久久久久久免费桃花 | 久草福利| 精品少妇一区二区三区在线播放 | 手机看片在线播放 | 国产女人与拘做受免费视频 | 日韩精品在线视频 | 久久国内精品 | 精品一区二区av | 国产亚洲精品久久午夜玫瑰园 | 亚洲成人在线视频播放 | 国产成人精品一区二 | a在线免费观看视频 | 久久久久久国产精品 | 一区精品视频在线观看 | 国产精品99久久久久 | 国产精品视频久久久 | 欧美狠狠操 | 欧美日韩综合一区 | 91久久精品 | 成人日批视频 | 国产成人精品一区二区三区在线 | 欧美国产一区二区三区 |