2015-04-05 105 views
0

爲什麼Arduino不能工作?Arduino上的無符號長按位移​​

unsigned long test = 1 << 20; 

我已經使用以下草圖測試了位移。

void setup() { 

    Serial.begin(9600); 

    unsigned long test = 0; 

    for(int i=0; i<32; i++) 
    { 
    test = 1 << i; 
    Serial.print("i:"); 
    Serial.print(i); 
    Serial.print(" dec:"); 
    Serial.println(test); 
    } 
} 

void loop() { 

} 

這給了我下面的輸出:

i:0 dec:1 
i:1 dec:2 
i:2 dec:4 
i:3 dec:8 
i:4 dec:16 
i:5 dec:32 
i:6 dec:64 
i:7 dec:128 
i:8 dec:256 
i:9 dec:512 
i:10 dec:1024 
i:11 dec:2048 
i:12 dec:4096 
i:13 dec:8192 
i:14 dec:16384 
i:15 dec:4294934528 <--- ??? 
i:16 dec:0   <--- ??? 
i:17 dec:0   <--- ??? 
i:18 dec:0   <--- ??? 
i:19 dec:0   <--- ??? 
i:20 dec:0   <--- ??? 
i:21 dec:0   <--- ??? 
i:22 dec:0   <--- ??? 
i:23 dec:0   <--- ??? 
i:24 dec:0   <--- ??? 
i:25 dec:0   <--- ??? 
i:26 dec:0   <--- ??? 
i:27 dec:0   <--- ??? 
i:28 dec:0   <--- ??? 
i:29 dec:0   <--- ??? 
i:30 dec:0   <--- ??? 
i:31 dec:0   <--- ??? 

在第15位和持續的,會發生什麼?

在Xcode中測試整個代碼給了我預期的輸出。

+1

因爲'1'不是'unsigned long' – 2015-04-05 17:31:15

+1

使用'1UL'作爲常量而不是'1'。 – 2015-04-05 17:35:23

+0

是的,做到了!謝謝你們 – Phil 2015-04-05 17:36:41

回答

3

int似乎目標機器上只有16位寬。 1是一個int,因此將其移位超過15位將調用未定義的行爲。解決方法很簡單,你應該使用long常數:

unsigned long test = 1UL << 20; 

你寫的語言是不完全的C,但這種方法仍然應該是正確的。

順便提一句,如果int是32位,則1 << 40會調用未定義的行爲。下面是一個簡單的測試:

#include <stdio.h> 

int a = 1, b = 40; 

int main() { 
    printf("1 << 40 = %d\n", 1 << 40); 
    printf("1 << 40 = %d\n", 1 << 40); 
    printf("1 << 40 = %d\n", 1 << 40); 
    printf("%d << %d = %d\n", a, b, a << b); 
} 

在有clang OS/X,我得到這樣的輸出:

~/dev/stackoverflow > make t42 
clang -O3 -Wall -o t42 t42.c 
t42.c:6:32: warning: shift count >= width of type [-Wshift-count-overflow] 
    printf("1 << 40 = %d\n", 1 << 40); 
          ^~~ 
t42.c:7:32: warning: shift count >= width of type [-Wshift-count-overflow] 
    printf("1 << 40 = %d\n", 1 << 40); 
          ^~~ 
t42.c:8:32: warning: shift count >= width of type [-Wshift-count-overflow] 
    printf("1 << 40 = %d\n", 1 << 40); 
          ^~~ 
3 warnings generated. 
~/dev/stackoverflow > ./t42 
1 << 40 = 1386850896 
1 << 40 = 256 
1 << 40 = 512 
1 << 40 = 256 
~/dev/stackoverflow > ./t42 
1 << 40 = 1477618256 
1 << 40 = 256 
1 << 40 = 512 
1 << 40 = 256 

clang警告有關問題的程序員和堅持產生不確定的行爲,與一貫不一致的輸出。令人驚訝的是不是?一個很好的例子,爲什麼一個人不應該忽略編譯器警告

+0

我沒有這麼說,但是Arduino開發語言的精確語義(參見http://arduino.cc/en/reference/homePage)可能不完全是那些C語言。 – chqrlie 2015-04-05 17:45:54

+0

你是對的Arduino Language!= C.不幸的是,使用的Arduino編譯器並沒有給你我在OSX上看到的警告 – Phil 2015-04-10 05:56:34

1

您正在轉移1這是一個16位的int。這可以工作到16384但是32768-327680x8000然後當被分配到unsigned long作爲0xFFFF8000,這是4294934528然後被簽名擴展。

+0

你的解釋是正確的,但應該指出,這種行爲不能依賴。將int引起溢出或過量引起未定義的行爲。 – chqrlie 2015-04-05 17:42:42

+0

@chqrlie我同意,並且移動以便改變符號位是UB。 – 2015-04-05 17:43:58

+0

'1 << 40'肯定會調用OS/X上未定義的行爲。 'clang'使得它證明了一點... – chqrlie 2015-04-05 17:51:46