gcc和clang产生不同的输出,而左移使用无符号值

rus*_*381 3 c c++ undefined-behavior language-lawyer

根据这篇关于c中未定义行为优化的有趣论文,表达式(x<<n)|(x>>32-n)"当n = 0时在C中执行未定义的行为".此stackoverflow讨论确认了负整数的行为未定义,并讨论了左移值的其他一些潜在缺陷.

请考虑以下代码:

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

uint32_t rotl(uint32_t x, uint32_t n)
{
    return (x << n) | (x >> (32 - n));
}

int main()
{
    uint32_t y = rotl(10, 0);
    printf("%u\n", y);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用以下参数进行编译: -O3 -std=c11 -pedantic -Wall -Wextra

  • 在gcc> 5.1.0中,程序的输出是10.
  • 在clang> 3.7.0中输出为4294967295.

有趣的是,在使用c ++编译时,这仍然是正确的:gcc结果,clang结果.

因此,我的问题如下:

  1. 它是从标准的语言我的理解,这应该不会发生未定义/实现定义的行为,因为这两个参数是无符号整数,没有价值的是负的.它是否正确?如果没有,c11和c ++ 11标准的相关部分是什么?
  2. 如果前一个语句为真,那么哪个编译器根据c/c ++标准生成正确的输出?直观地说,左移无数字应该可以返回值,即gcc输出的值.
  3. 如果不是这种情况,为什么没有警告,由于左移溢出,此代码可能会调用未定义的行为?

Bar*_*rry 7

来自[expr.shift],强调我的:

如果右操作数为负数,或者大于或等于提升左操作数的位长度,则行为未定义.

你在做:

(x >> (32 - n))
Run Code Online (Sandbox Code Playgroud)

n == 0,所以你右移32中的32位数字.因此,UB.

  • @ ruser45381是的,这是直接引用.可能只是无法弄清楚它需要警告(例如,只需键入`x >> 32`警告).毕竟,编译器没有*警告 - 这是一个QoI问题. (2认同)