2015-04-05 180 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