这是g ++中的错误吗?

hel*_*.co 20 c++ gcc

#include <stdint.h>
#include <iostream>

using namespace std;

uint32_t k[] = {0, 1, 17};

template <typename T>
bool f(T *data, int i) {
    return data[0] < (T)(1 << k[i]);
}

int main() {
    uint8_t v = 0;
    cout << f(&v, 2) << endl;
    cout << (0 < (uint8_t)(1 << 17)) << endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)


g++ a.cpp && ./a.out
1
0
Run Code Online (Sandbox Code Playgroud)

为什么我得到这些结果?

Ste*_*fan 20

它看起来像gcc反转移位并将其应用到另一侧,我想这是一个错误.

在C(而不是C++)中,同样的事情发生了,C转换为asm更容易阅读,所以我在这里使用C; 我还减少了测试用例(删除模板和k数组).foo()是原始的buggy f()函数,foo1()是foo()的行为与gcc一样但不应该,并且bar()显示除了指针读取之外的foo()应该是什么样子.

我是64位,但32位是参数处理和找到k相同的.

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

uint32_t k = 17;
char foo(uint8_t *data) {
    return *data < (uint8_t)(1<<k);
/*
with gcc -O3 -S: (gcc version 4.7.2 (Debian 4.7.2-5))
    movzbl  (%rdi), %eax
    movl    k(%rip), %ecx
    shrb    %cl, %al
    testb   %al, %al
    sete    %al
    ret
*/
}
char foo1(uint8_t *data) {
    return (((uint32_t)*data) >> k) < 1;
/*
    movzbl  (%rdi), %eax
    movl    k(%rip), %ecx
    shrl    %cl, %eax
    testl   %eax, %eax
    sete    %al
    ret
*/
}
char bar(uint8_t data) {
    return data < (uint8_t)(1<<k);
/*
    movl    k(%rip), %ecx
    movl    $1, %eax
    sall    %cl, %eax
    cmpb    %al, %dil
    setb    %al
    ret
*/
}

int main() {
    uint8_t v = 0;
    printf("All should be 0: %i %i %i\n", foo(&v), foo1(&v), bar(v));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • *最后*格言"过早优化是所有邪恶的根源"的情况*真的*适用! (2认同)
  • 如果您想要比asm更容易阅读的内容,请尝试使用gcc中的-fdump-tree-all选项. (2认同)

Ale*_*nze 8

如果你的int是16位长,那么你将遇到未定义的行为,结果是"OK".

将N位整数向左或向右移位N位或更多位会导致未定义的行为.

由于这种情况发生在32位整数中,这是编译器中的一个错误.

  • 我认为gcc中存在一个错误,这篇文章没有回答OP. (4认同)
  • @interjay然后,除非我遗漏了什么,否则它看起来像一个bug. (2认同)