TYPE BASE LENGTH RELOCATION SEGMENT NAME ---------------------------------------------------------------------------------------------- IDATA 0080H 0034H UNIT _IDATA_GROUP_ IDATA 00B4H 0022H UNIT ?ID?IPPHONE_MAIN IDATA 00D6H 001FH UNIT ?ID?DNS_NICRCV?IPPHONE_DNS IDATA 00F5H 0004H UNIT ?ID?DISP IDATA 00F9H 0001H UNIT ?STACK 這上面標(biāo)有STACK的段就是堆棧分配,上面的數(shù)據(jù)表明,SP堆棧指針安排在F9H這個地址,堆棧空間是1個字節(jié)!表面看沒有溢出,但我的程序里使用了中斷服務(wù),進入中斷服務(wù)時,至少需要8個字節(jié)的堆??臻g(保存R0~R7寄存器)來進行保護現(xiàn)場,8051使用的是遞增壓棧的設(shè)計,堆棧指針往往被安排在內(nèi)存空間的后面可用部分,每壓棧一個字節(jié),SP指針往上加1,進中斷服務(wù)時,至少壓棧8個字節(jié),F(xiàn)9H+8,超出了FFH,堆棧指針不能超過FFH,也就是說堆棧溢出了!原來這就是導(dǎo)致程序不斷重啟的原因,不是變量內(nèi)存溢出,而是堆棧溢出! 而當(dāng)我把那個數(shù)組指定為xdata類型后,由于該數(shù)組不再占用idata區(qū),于是IDATA一下子多了16個字節(jié)的可用空間,重新編譯后的M51這樣安排: IDATA 0080H 0024H UNIT _IDATA_GROUP_ IDATA 00A4H 0022H UNIT ?ID?IPPHONE_MAIN IDATA 00C6H 001FH UNIT ?ID?DNS_NICRCV?IPPHONE_DNS IDATA 00E5H 0004H UNIT ?ID?DISP IDATA 00E9H 0001H UNIT ?STACK 從這組數(shù)據(jù)來看,SP指針安排到在E9H這個地址,堆??臻g有FFH-E9H+1=23個字節(jié),對于程序來說已經(jīng)夠用,因此程序運行正常。 多次調(diào)整變量類型的編譯結(jié)果表明,C51對于堆棧空間需求大小不作計算,任何代碼都只是按堆棧空間只有1個字節(jié)需求來分配(在我眼里看來這明顯是胡來,稍復(fù)雜點的子程序調(diào)用都不可能只要1個字節(jié)就能完成現(xiàn)場保護),由于堆棧只能分配在data區(qū)和idata區(qū),因此當(dāng)一個程序為了優(yōu)化而data區(qū)占用太多時,雖然編譯器能編譯成功,但往往SP堆棧指針被分配在data區(qū)的最后面,很容易造成堆棧空間不夠而溢出。為保險起見,最好保證編譯后的SP值安排在F0H之前,那樣至少有16個字節(jié)的堆??臻g,才能最大限度保證程序不會跑飛。 看樣子不能太相信Keil C51,以后編譯完后,還得查看一下M51才能確保程序的質(zhì)量,不知道這個算不算Keil C51的bug。