【问题标题】:Defining array of long long int定义 long long int 数组
【发布时间】:2014-08-05 14:24:31
【问题描述】:

我正在尝试生成一个数组,该数组将容纳从 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;

并打印它的值,它正在工作。我哪里错了?

【问题讨论】:

标签: c++ c arrays long-integer


【解决方案1】:

您的问题出在以下代码中:a[i] = 2 &lt;&lt; (i-1);

2 假定为 int 类型,因为在大多数 C++ 编译器中它是 32 位。

你需要用这个覆盖它。

a[i] = 2ULL &lt;&lt; (i-1);

您需要特别注意与移位运算符一起使用的类型,移动更多位以使操作数的大小为未定义行为,并且此处可能发生任何事情(sample),由于忘记了后缀,因此需要更多预防措施.

【讨论】:

    【解决方案2】:

    其他答案已经回答了您提出的问题,但是您的代码中还有其他一些问题。

    要扩展其他答案,请记住,C 表达式的类型通常由表达式本身决定,而不是由它出现的上下文决定。你有:

    a[i]=2<<(i-1);
    

    赋值左侧是unsigned long long int 类型的事实不会影响右侧类型int 的求值,而&lt;&lt; 会导致int 溢出。

    没有必要将数组的元素 0 视为特殊情况。

    比起2 &lt;&lt; (i-1),或者更正确的2ULL &lt;&lt; (i-1),写1ULL &lt;&lt; i更直接。

    您为变量使用了错误的printf 格式字符串。 iunsigned long long 类型; "%d" 需要 int 类型的参数。但由于i 只是从 0 到 65,它也可能是一个inta 的元素属于 unsigned long long int 类型,但您使用的格式为 signed long long int

    这是您的 program 代码 sn-p 的修改版本,充实为完整的程序并纠正了上述问题:

    #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]);
        }
    }
    

    【讨论】:

    • printf 语句只是为了测试目的,在发布之前我尝试了一些东西,所以让 i as long int。
    • @user1551574:当然可以,但即使只是为了测试目的(也许尤其是如果是为了测试目的),使用正确的格式字符串也是值得的。
    【解决方案3】:

    问题在于这一行:

    2<<(i-1)
    ^
    

    2 是整数文字,因此结果是 int 而不是 unsigned long long 您可以使用 ULL 后缀来解决此问题。

    使用大于提升的左操作数的位长度的移位也是未定义的行为。您在使用printf 时也有未定义的行为。您使用了不正确的格式说明符,在这两种情况下您都应该使用%llu

    使用正确的警告标志可能会帮助您捕获所有这些错误,例如使用以下标志 -fsanitize=undefined -Wall -Wextra -Wconversion -pedanticclang 会给出以下警告:

     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'
    

    【讨论】:

      【解决方案4】:

      使用 %llu 扫描 unsigned long long int 而不是您在扫描时所做的 %lld

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-05-10
        • 1970-01-01
        • 1970-01-01
        • 2016-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多