我正在尝试生成一个从2 ^ 0到2 ^ 63保持2的幂的数组。我正在使用unsigned long long int。但是当我打印所有值时,它会打印到2 ^ 30然后它会溢出。编译器是GNU GCC版本4.8.1。这是代码。
unsigned long long int a[65],i;
a[0]=1;
for(i=1;i<65;i++) {
a[i]=2<<(i-1);
printf("i=%d a[i]=%lld\n",i, a[i]);
}
这是输出
i=1 a[i]=2
i=2 a[i]=4
i=3 a[i]=8
i=4 a[i]=16
i=5 a[i]=32
i=6 a[i]=64
i=7 a[i]=128
i=8 a[i]=256
i=9 a[i]=512
i=10 a[i]=1024
i=11 a[i]=2048
i=12 a[i]=4096
i=13 a[i]=8192
i=14 a[i]=16384
i=15 a[i]=32768
i=16 a[i]=65536
i=17 a[i]=131072
i=18 a[i]=262144
i=19 a[i]=524288
i=20 a[i]=1048576
i=21 a[i]=2097152
i=22 a[i]=4194304
i=23 a[i]=8388608
i=24 a[i]=16777216
i=25 a[i]=33554432
i=26 a[i]=67108864
i=27 a[i]=134217728
i=28 a[i]=268435456
i=29 a[i]=536870912
i=30 a[i]=1073741824
i=31 a[i]=-2147483648
i=32 a[i]=0
i=33 a[i]=2
i=34 a[i]=4
i=35 a[i]=8
i=36 a[i]=16
i=37 a[i]=32
i=38 a[i]=64
i=39 a[i]=128
i=40 a[i]=256
i=41 a[i]=512
i=42 a[i]=1024
i=43 a[i]=2048
i=44 a[i]=4096
i=45 a[i]=8192
i=46 a[i]=16384
i=47 a[i]=32768
i=48 a[i]=65536
i=49 a[i]=131072
i=50 a[i]=262144
i=51 a[i]=524288
i=52 a[i]=1048576
i=53 a[i]=2097152
i=54 a[i]=4194304
i=55 a[i]=8388608
i=56 a[i]=16777216
i=57 a[i]=33554432
i=58 a[i]=67108864
i=59 a[i]=134217728
i=60 a[i]=268435456
i=61 a[i]=536870912
i=62 a[i]=1073741824
i=63 a[i]=-2147483648
i=64 a[i]=0
我也尝试过使用int64_t,但结果是一样的。如果我通常喜欢
unsigned long long int lli = 9223372036854775807;
并打印它的价值,它正在发挥作用。我哪里错了?
答案 0 :(得分:4)
您的问题出在以下代码中:a[i] = 2 << (i-1);
2
假定类型为int
,因为它在大多数C ++编译器中都是32位。
您需要使用。
覆盖它 a[i] = 2ULL << (i-1);
你需要特别注意与移位运算符一起使用的类型,移动更多的位,操作数的大小是未定义的行为,这里可能发生任何事情(sample),因为文字需要更多的预防措施忘了后缀。
答案 1 :(得分:3)
其他答案已经回答了您提出的问题,但您的代码中还存在其他一些问题。
要扩展其他答案,请记住C表达式的类型通常由表达式本身决定,而不是由它出现的上下文决定。你有:
a[i]=2<<(i-1);
分配的左侧属于unsigned long long int
类型的事实不影响右侧的评估,int
类型,而<<
导致int
溢出。
没有必要将数组的元素0视为一种特殊情况。
而不是2 << (i-1)
,或更正确2ULL << (i-1)
,写1ULL << i
更为直接。
您为变量使用了错误的printf
格式字符串。 i
的类型为unsigned long long
; "%d"
需要int
类型的参数。但由于i
只是从0到65,因此它也可能是int
。 a
的元素属于unsigned long long int
类型,但您使用的格式为已签名 long long int
。
以下是 program 代码段的修改版本,充实到完整的程序并纠正了上述问题:
#include <stdio.h>
int main(void) {
unsigned long long int a[65];
int i;
for(i=0;i<65;i++) {
a[i] = 1ULL << i;
printf("i=%d a[i]=%llu\n", i, a[i]);
}
}
答案 2 :(得分:2)
问题在于这一行:
2<<(i-1)
^
2
是一个整数文字,因此结果是 int 而不是 unsigned long long 您可以使用ULL
后缀来解决这个问题。
使用等于大于提升左操作数的位长度的移位也是未定义的行为。您在使用printf
时也有未定义的行为。您使用的格式说明符不正确,在这两种情况下都应使用%llu
。
使用正确的警告标志可能会帮助您捕获所有这些错误,例如使用以下标志-fsanitize=undefined -Wall -Wextra -Wconversion -pedantic
并clang
发出以下警告:
warning: implicit conversion changes signedness: 'int' to 'unsigned long long' [-Wsign-conversion]
a[i]=2<<(i-1);
~~^~~~~~~
warning: format specifies type 'int' but the argument has type 'unsigned long long' [-Wformat]
printf("i=%d a[i]=%lld\n",i, a[i]);
~~ ^
%llu
以及以下运行时错误:
runtime error: left shift of 2 by 31 places cannot be represented in type 'int'
答案 3 :(得分:0)
使用%llu扫描无符号的long long int而不是您扫描时执行的%lld