Arduino 上的按位移位 unsigned long
Bitwise shift unsigned long on 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
,这是一个 16 位 int
。这适用于 16384
,但 32768
是 -32768
或 0x8000
,然后在分配给 unsigned long
时符号扩展为 0xFFFF8000
,即4294934528
.
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);
}
在 OS/X 和 clang
上,我得到这个输出:
~/dev/Whosebug > 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/Whosebug > ./t42
1 << 40 = 1386850896
1 << 40 = 256
1 << 40 = 512
1 << 40 = 256
~/dev/Whosebug > ./t42
1 << 40 = 1477618256
1 << 40 = 256
1 << 40 = 512
1 << 40 = 256
clang
警告程序员该问题并坚持生成未定义的行为,输出始终不一致。是不是很神奇?一个很好的例子,说明为什么永远不要忽略编译器警告
为什么以下在 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
,这是一个 16 位 int
。这适用于 16384
,但 32768
是 -32768
或 0x8000
,然后在分配给 unsigned long
时符号扩展为 0xFFFF8000
,即4294934528
.
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);
}
在 OS/X 和 clang
上,我得到这个输出:
~/dev/Whosebug > 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/Whosebug > ./t42
1 << 40 = 1386850896
1 << 40 = 256
1 << 40 = 512
1 << 40 = 256
~/dev/Whosebug > ./t42
1 << 40 = 1477618256
1 << 40 = 256
1 << 40 = 512
1 << 40 = 256
clang
警告程序员该问题并坚持生成未定义的行为,输出始终不一致。是不是很神奇?一个很好的例子,说明为什么永远不要忽略编译器警告