一個(gè)從定時(shí)計(jì)數(shù)器賦初值引起的故事
在一天李老師看到我的學(xué)生作業(yè)都是寫TH0=(-10000)/256.;TL0=(-10000)%256;她說-10000可能使用不對(duì)。當(dāng)天晚上的時(shí)候在QQ上發(fā)消息過來說,經(jīng)驗(yàn)證,在Keil中,TH0=(65536-10000)/256;TL0=(65536-10000)%256;的賦值方式TH0=0xD8,TL0=0xF0。但是TH0=(-10000)/256.;TL0=(-10000)%256;的賦值方式TH0=0xD9,TL0=0xF0。TH0的數(shù)值總是要大1,而且取不同的數(shù)值驗(yàn)證均是這個(gè)結(jié)果,兩種方式TH0總是相差1,而TL0數(shù)值是一樣的。我打開Keil,輸入程序,然后調(diào)試查看匯編指令,得到如下結(jié)果:
本文引用地址:http://www.ex-cimer.com/article/201611/323235.htm8: TH0=(65536-10000)/256;
C:0x009B 758CD8 MOV TH0(0x8C),#0xD8
9: TH1=(-10000)/256;
C:0x009E 758DD9 MOV TH1(0x8D),#0xD9
發(fā)現(xiàn)匯編指令直接對(duì)于TH0和TH1進(jìn)行賦值,沒有經(jīng)過任何的運(yùn)算,但是就是相差1,這是為什么呢?我無法理解,后來在百度知道上提問,得到的回答是:這個(gè)和默認(rèn)數(shù)據(jù)類型有關(guān),TH0=(65536-10000)/256,默認(rèn)unsigned char,即TH0=0xD8;TH0=(-10000)/256,默認(rèn)signed char,二進(jìn)制最高位為符號(hào)位,負(fù)數(shù)為1,所以TH0=0xD9 。
原來是Keil編譯器計(jì)算數(shù)據(jù)的時(shí)候默認(rèn)的數(shù)據(jù)類型不一樣,65536-10000=55536是unsigned類型,55536/256=216=0xD8,而-10000是signed類型,(-10000)/256=-39=0xD9。原來如此,Keil的編譯器預(yù)先處理的時(shí)候根據(jù)不同類型的數(shù)據(jù)進(jìn)行了不同的運(yùn)算,然后直接賦值。我又驗(yàn)證了一下,TH0=(unsigned int)(-10000)/256;發(fā)現(xiàn)先把-10000強(qiáng)制轉(zhuǎn)換為unsigned類型后,得到的結(jié)果就是正確的了TH0=0xD8。得到答案后臉紅了,不過多虧是在放假期間,沒有學(xué)生看到。開學(xué)后立即在課堂上更正了。╮(╯▽╰)╭,這次糗大了。
我重新寫了一個(gè)程序,#include
void main()
{
unsigned int i;
unsigned char j;
i= - 10000;
j=i/256;
while(1)
;
}
中間加一個(gè)變量,看Keil會(huì)怎么處理,結(jié)果發(fā)現(xiàn)
2: void main()
3: {
4: unsigned int i;
5: unsigned char j;
6: i=-10000;
C:0x000F 7ED8 MOV R6,#0xD8
7: j=i/256;
8:
C:0x0011 8E08 MOV 0x08,R6
9: while(1)
C:0x0013 80FE SJMP C:0013
還是直接賦值,編譯器太聰明了,知道80C51對(duì)于數(shù)據(jù)運(yùn)算非常非常的不擅長,于是直接處理完數(shù)據(jù),然后用賦值的方式來寫匯編的指令。而且還知道,i的低字節(jié)沒有用到,在指令里根本沒有出現(xiàn),這也太聰明了吧。Keil軟件是最流行,最好用的編譯器,不是浪得虛名的。
我再修改:
include
void main()
{
unsigned int i;
unsigned char j;
i=-10000;
i++;
j=i/256;
while(1)
;
}
結(jié)果發(fā)現(xiàn)代碼只增加了一點(diǎn)。
2: void main()
3: {
4: unsigned int i;
5: unsigned char j;
6: i=-10000;
C:0x0003 7FF0 MOV R7,#B(0xF0)
C:0x0005 7ED8 MOV R6,#0xD8
7: i++;
C:0x0007 0F INC R7
C:0x0008 BF0001 CJNE R7,#0x00,C:000C
C:0x000B 0E INC R6
8: j=i/256;
9:
C:0x000C 8E08 MOV 0x08,R6
10: while(1)
C:0x000E 80FE SJMP C:000E
但對(duì)于j的運(yùn)算還是用賦值的方式。我再改,把i類型變成signed類型,結(jié)果大吃一驚:
include
void main()
{
int i;
unsigned char j;
i=-10000;
j=i/256;
while(1)
;
}
評(píng)論