gcc中的优化级别改变了c程序的行为

use*_*769 20 c optimization gcc bit-manipulation shift

在gcc中使用不同的优化级别编译此代码时,我看到了我不期望的行为.

函数测试应使用1填充64位无符号整数,将shift_size位向左移位,并将32位低位作为32位无符号整数返回.

当我用-O0编译时,我得到了我期望的结果.

当我使用-O2编译时,如果我尝试移位32位或更多,我就不会.

实际上,如果我在x86上移位大于或等于位宽的32位整数,那么我得到的结果就是我所期望的结果,这是仅使用移位大小的5个低位的移位.

但我正在转移64位数字,所以转移<64应该是合法的吗?

我认为这是我的理解中的错误而不是编译器中的错误,但我无法弄明白.

我的机器:gcc(Ubuntu/Linaro 4.4.4-14ubuntu5)4.4.5 i686-linux-gnu

#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>

uint32_t test(unsigned int shift_size) {
    uint64_t res = 0;
    res = ~res;
    res = res << shift_size; //Shift size < uint64_t width so this should work
    return res; //Implicit cast to uint32_t
}

int main(int argc, char *argv[])
{
    int dst;
    sscanf(argv[1], "%d", &dst); //Get arg from outside so optimizer doesn't eat everything
    printf("%" PRIu32 "l\n", test(dst));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

用法:

$ gcc -Wall -O0 test.c 
$ ./a.out 32
0l
$ gcc -Wall -O2 test.c 
$ ./a.out 32
4294967295l
Run Code Online (Sandbox Code Playgroud)

gcc -S -Wall -O0 test.c

gcc -S -Wall -O2 test.c

pmg*_*pmg 5

"%u"(或"%lu")uint32_t并不一定兼容.尝试

    #include <inttypes.h>

    //printf("%ul\n", test(dst));
    printf("%" PRIu32 "l\n", test(dst));
Run Code Online (Sandbox Code Playgroud)

uint32_t使用"%u"(或"%lu")说明符打印值可以调用未定义的行为.


Lin*_*cer 1

它看起来像一个错误。我的猜测是编译器已经折叠了最后两行:

res = res << shift_size
return (uint32_t)res;
Run Code Online (Sandbox Code Playgroud)

进入:

return ((uint32_t)res) << shift_size;
Run Code Online (Sandbox Code Playgroud)

后者现在已明确定义为 32 或更大。