【问题标题】:shift count >= width of type warning for 64 bit but not 32 bit移位计数 >= 64 位但不是 32 位的类型警告宽度
【发布时间】:2022-01-02 04:29:27
【问题描述】:

我收到 test1 的“班次计数 >= 类型宽度”警告,但 test3 没有收到同样的警告。所有测试似乎都有效,并且铸造摆脱了警告。但是,我不明白为什么我没有收到关于 test3 的类似警告。

test1 和 test2 在我的机器上是 64 位长类型,而 test3 和 test4 在我的机器上是 32 位 int 类型。我使用与此类似的代码来打包/解包数据以通过网络发送。我已经重写了它以适应这个问题。

unsigned char arr1[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
unsigned char arr2[4] = {0xFF, 0xFF, 0xFF, 0xFF};
long test1;
long test2;
int test3;
int test4;

// Gives warning: shift count >= width of type
test1 = (arr1[0] << 56) | (arr1[1] << 48) | (arr1[2] << 40) | (arr1[3] << 32)
    | (arr1[4] << 24) | (arr1[5] << 16) | (arr1[6] << 8) | arr1[7];
printf("Test 1: %lX\n", test1);

// No warning
test2 = ((long)arr1[0] << 56) | ((long)arr1[1] << 48) | ((long)arr1[2] << 40)
    | ((long)arr1[3] << 32) | ((long)arr1[4] << 24) | ((long)arr1[5] << 16)
    | ((long)arr1[6] << 8) | (long)arr1[7];
printf("Test 2: %lX\n", test2);

// No warning. Shouldn't this give a warning?
test3 = (arr2[0] << 24) | (arr2[1] << 16) | (arr2[2] << 8) | arr2[3];
printf("Test 3: %X\n", test3);

// No warning
test4 = ((int)arr2[0] << 24) | ((int)arr2[1] << 16) | ((int)arr2[2] << 8)
    | (int)arr2[3];
printf("Test 4: %X\n", test4);

【问题讨论】:

    标签: c compiler-warnings bit-shift


    【解决方案1】:

    由于整数促销,在案例 3 中没有警告。

    一般来说,当在表达式中使用小于int 的类型时,它首先被提升为int。例如,当你这样做时:

    arr2[0] << 24
    

    arr2[0] 的类型为unsigned char,但该值首先被提升为int,然后被提升的值被移位。所以case 3和case 4其实是一样的。

    这里要注意的一点是,由于提升为有符号类型,您可能会将值为 1 的位移入符号位。这样做会触发undefined behavior

    处理此问题的最安全方法是在移位之前将每个值转换为适当大小的无符号类型,并将结果分配给正确的无符号类型。还要注意特定大小的printf 格式说明符的宏。

    unsigned char arr1[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    unsigned char arr2[4] = {0xFF, 0xFF, 0xFF, 0xFF};
    uint64_t test2;
    uint32_t test4;
    
    test2 = ((uint64_t)arr1[0] << 56) | ((uint64_t)arr1[1] << 48)
          | ((uint64_t)arr1[2] << 40) | ((uint64_t)arr1[3] << 32)
          | ((uint64_t)arr1[4] << 24) | ((uint64_t)arr1[5] << 16)
          | ((uint64_t)arr1[6] << 8)  | (uint64_t)arr1[7];
    printf("Test 2: %" PRIX64 "\n", test2);
    
    test4 = ((uint32_t)arr2[0] << 24) | ((uint32_t)arr2[1] << 16) 
          | ((uint32_t)arr2[2] << 8)  | (uint32_t)arr2[3];
    printf("Test 4: %" PRIX32 "\n", test4);
    

    【讨论】:

    • 很好 - 虽然您可能希望 X 版本 PRIX32 而不是 PRIu32 模仿 OP 的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多