WinAVR(AVR-GCC)的奇怪問題
(這篇是從舊文章整理出來的)
GCC在compile的時候可以用-o的參數來設定optimize的程度,可設為不作最佳化(-○0),或是-o1~3和-os幾種最佳化的等級。-o0的時候是不會有什麼問題啦,不過程式不作optimize的話塞不進Tiny2313裏面。所以程式才寫到大概一半大小的時候就開始用最佳化compile,然後就發現有個地方一直很奇怪…..。
來看一小段程式:
tmp = RRR / 5 - 3; // tmp型別為int,所以不會取到小數部份
if (tmp > 5) {
AAA = 5;
} else if (tmp < 1) {
AAA = 1;
} else if (((RRR % 5) * 10 / 5) > 4) { // 手動四捨五入
AAA = tmp + 1;
}
這段程式主要是要把RRR轉換成AAA 1~5的數值。RRR正常是20~40,有時會超出這個範圍,所以用了兩個判斷式去限制住讓AAA不會爆掉,就這麼簡單而已。
然後…我發現不管RRR的數值是多少,他在第一個else if的地方程式執行時總認為tmp=0,所以,判斷式就成立,結果就是AAA永遠=1。
怪吧?更怪的是在如果第一個if前面先去判斷tmp的值來看看,他會告訴你tmp不等於0…。然後才過了兩行程式,tmp就變0了。
裏面所有的變數都是宣告為signed int,跟其它變數也都沒有衝突的問題。而且只要compile的時候不要作optimize,就一切正常,所以程式本身應該是沒問題的。
結果怎麼解?我把tmp拿掉就好了…直接寫成:
AAA = RRR / 5 - 3;
if (AAA > 5) {
AAA = 5;
} else if (AAA < 1) {
AAA = 0;
} else if (((RRR % 5) * 10 / 5) > 4) { // 手動四捨五入
AAA++;
}
這樣跑起來就正常了(?),看來大概這compiler討厭我的tmp吧?好吧,不去管原因了,就先加減用。結果過沒兩天我改了程式的其它不相干的地方之後,他又壞了。
這次一樣壞在第一個else if的地方,他總認為AAA = 0…最後又讓AAA變成永遠=1。 (你那麼愛讓AAA=1嗎?)
我只好再換另一種寫法:
AAA = RRR / 5;
if (AAA > 8) {
AAA = 8;
} else if (AAA < 4) {
AAA = 4;
} else if (((RRR % 5) * 10 / 5) > 4) { // 手動四捨五入
AAA++;
}
AAA -= 4
把減4的動作移到最後面再作,這樣就又好了….這什麼道理?
所以…
有遇到程式跑起來很奇怪的時候,試試看先把compile optimize設成-o0吧