其他分享
首页 > 其他分享> > 使用gcc进行逐位移位的意外行为

使用gcc进行逐位移位的意外行为

作者:互联网

我有一个这样的测试程序:

int main()
{
    unsigned n = 32;

    printf("ans << 32 = 0x%X\n", (~0x0U) << 32);
    printf("ans >> 32 = 0x%X\n", (~0x0U) >> 32);

    printf("ans << n(32) = 0x%X\n", (~0x0U) << n);
    printf("ans >> n(32) = 0x%X\n", (~0x0U) >> n);

    return 0;
}  

它产生以下输出:

ans << 32 = 0x0  ... (1)  
ans >> 32 = 0x0  ... (2)  
ans << n(32) = 0xFFFFFFFF  ... (3)  
ans >> n(32) = 0xFFFFFFFF  ... (4)   

我期望(1)和(3)是相同的,以及(2)和(4)是相同的.

使用gcc版本:gcc.real(Ubuntu 4.4.1-4ubuntu9)4.4.1

怎么了?

解决方法:

根据C standard,第6.5.7.3节,根据类型的大小进行移位是未定义的行为:

6.5.7 Bitwise shift operators
(…) If the value of
the right operand is negative or is greater than or equal to the width
of the promoted left operand, the behavior is undefined.

您的编译器应该警告您:

$gcc shift.c -o shift -Wall
shift.c: In function ‘main’:
shift.c:5:5: warning: left shift count >= width of type [enabled by default]
shift.c:6:5: warning: right shift count >= width of type [enabled by default]

如果你看一下assembler code gcc正在生成,你会发现它实际上是在编译时计算前两个结果.简化:

main:
    movl    $0, %esi
    call    printf

    movl    $0, %esi
    call    printf

    movl    -4(%rbp), %ecx  ; -4(%rbp) is n
    movl    $-1, %esi
    sall    %cl, %esi       ; This ignores all but the 5 lowest bits of %cl/%ecx
    call    printf

    movl    -4(%rbp), %ecx
    movl    $-1, %esi
    shrl    %cl, %esi
    call    printf

标签:c-3,linux,gcc,bit-shift
来源: https://codeday.me/bug/20190726/1541930.html