unexpected behavior of bitwise shifting using gcc

僤鯓⒐⒋嵵緔 提交于 2019-11-28 09:18:37

问题


I have a test program like this:

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;
}  

It produces the following output:

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

I was expecting (1) and (3) to be the same, as well as (2) and (4) to be the same.

Using gcc version: gcc.real (Ubuntu 4.4.1-4ubuntu9) 4.4.1

What is happening?


回答1:


Shifting by the size of the type is undefined behavior, according to the 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.

Your compiler should warn you about this:

$ 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]

If you look at the assembler code gcc is generating, you'll see it is actually calculating the first two results at compilation time. Simplified:

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


来源:https://stackoverflow.com/questions/7214263/unexpected-behavior-of-bitwise-shifting-using-gcc

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!