2015/12/26

Arduino小冷門知識:char不一定是-128到127

當我宣告char變數、並把它當作整數來使用的話,我預期它的大小會是1位元組,而合法範圍是-128到127、或是0到255,因為char可能是signed或unsigned,由C語言實作決定。

但卻發現違反上述說法的例子。

程式碼如下:
char x_global = 0;

void setup(){
    Serial.begin(115200);
}

void loop(){
    char x_local = 0;
   
    while(1){
        Serial.print(int(x_global));
        Serial.print("  ");
        Serial.print(int(x_local));
        Serial.println("");
        x_global++;
        x_local++;
        delay(100);
    }
}


全域變數x_global、區域變數x_local,不斷地加1並印出。

x_global的值符合預期,從0、1、2、3...到127,然後會到-128,接著是-127、-126、-125...到-1,然後又回到0。

但x_local不如預期,從0、1、2、3...到127,然後到128、129、130、一直變大、可超過幾百、幾千。

Arduino 1.0.6會有上述奇怪的行為。不過在Arduino 1.6.7就不會有。

若改成signed char,行為同上。

若改成unsigned char,那麼兩個變數都會從0、1、2、3...到255,然後回到0、1、2...。

7 comments:

  1. 你好!
    最近再用ARDUINO碰到一個問題想請問大師,
    我想設兩個人體紅外線感測,設定一個"人數"函數,一邊碰到人數加1,一邊人數減1,
    但設定紅外線感測人時,函數+1,他會持續增加,我只想加一次,不知怎解決。
    我有想過用當紅外線偵測1時在跳回0時那一剎那在+1但不知道怎寫,請問該如何是好?

    ReplyDelete
    Replies
    1. 紅外線PIR感測器,應有兩個旋鈕,請參閱相關文件,了解各自能夠調整什麼,這會影響程式寫法。
      使用時,人潮多寡與流動速率,也會影響判斷。

      至於程式的部份,寫法很多種,譬如可以設時距,當紅外線偵測到1,就加1,然後暫停一小時間,此時間內不動作。那段時間通常可以取人走過通過的最短時間。

      感覺很難做得精準正確,我沒完整的實際經驗,無法幫你。

      Delete
  2. 宣告 char 而到底是 unsigned char 或是 signed char 是 compiler 實作來決定的, 如果你需要 signed char, 需要明確寫出 signed char x_global, int 則不會有這個問題, 只有 char 有這樣的需要。

    http://descent-incoming.blogspot.tw/2013/02/c-char-signed-unsigned.html

    ReplyDelete
    Replies
    1. 謝謝,很久以前應該記得這件事,後來就忘了。

      不過即便如此,仍無法說明這篇的疑惑。
      因為x_local不僅會超過128,還會繼續增加,超過幾百、幾千。
      我猜1.0.6版的C編譯器,大概讓x_local佔一個int,但是卻沒有檢查溢位的情況。

      Delete
  3. x_local有看過會再多少的時候不再加上去嗎?
    應該是個bug .. 但好奇他是被設成什麼了

    ReplyDelete
  4. 依照 C standard 來說, signed 變數 overflow 是 undefined behavior, 所以出什麼都不意外這樣..
    不過不知道 arduino 用的 C 自己是怎麼規定的...

    ReplyDelete