羞羞小视频在线观看_羞羞视频免费入口网站_羞羞视频下载APP_男女羞羞视频软件

歡迎光臨東莞市飛江電子科技有限公司官網(wǎng)!
全國(guó)咨詢(xún)熱線(xiàn)

13926563901

18925580829

飛江淘寶店鋪

首頁(yè)>技術(shù)資料>51單片機(jī)

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

發(fā)布時(shí)間:2018-03-26   瀏覽量:

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

 

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

  平臺(tái):MEGA64;

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

  問(wèn)題:一個(gè)全局變量在定義的時(shí)候直接賦值為0,但在程序運(yùn)行過(guò)程中,沒(méi)有改變?cè)撟兞康牟僮?,可是奇怪的是,程序在運(yùn)行一段時(shí)間之后,這個(gè)全局變量居然自動(dòng)改變了。

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

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

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

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

  一開(kāi)始我沒(méi)有弄懂他的意思。明白之后,我覺(jué)得很有可能,不過(guò),仔細(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。一般來(lái)說(shuō),就算是函數(shù)多層嵌入也不可能占如此之大的空間,網(wǎng)上說(shuō),就算浮點(diǎn)函數(shù),40B都已經(jīng)足夠。

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

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

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


 

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

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

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

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

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

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

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

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

  有一個(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

    {

      *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本來(lái)指向一個(gè)4位的數(shù)組temp[4],現(xiàn)在由于pTemp++超過(guò)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ù),而且,跨過(guò)數(shù)據(jù)堆棧與全局變量區(qū)域的界限,直接修改了全局變量的某些值!

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

 

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