当前位置: 首页 > 知识库问答 >
问题:

gcc和clang在具有无符号值的左移时产生不同的输出

汪成仁
2023-03-14

根据这篇关于c语言中未定义行为优化的有趣文章,表达式(x

考虑以下代码:

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

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

  • 在gcc中

有趣的是,当使用c编译时,这仍然是正确的:gcc结果,clangresults。

因此,我的问题如下:

  1. 我从标准中的语言中理解,这不应该调用未定义/实现定义的行为,因为两个参数都是无符号整数,并且没有一个值是负的。这是正确的吗?如果不是,c11和c 11的相关部分是什么?
  2. 如果前面的语句为真,哪个编译器正在根据c/c标准产生正确的输出?直观地说,左移没有数字应该会给您返回值,即gcc输出的内容。
  3. 如果上述情况并非如此,为什么没有警告此代码可能会因左移溢出而调用未定义的行为?

共有3个答案

公西修文
2023-03-14

如果n为0,32-n为32,由于x有32位,x

链接SO帖子中的问题是不同的。这个与签名无关。

养枫涟
2023-03-14

你的n0,所以执行x

莘羽
2023-03-14

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

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

你正在做:

(x >> (32 - n))

使用n==0,则将32位数字右移32位。因此,乌布。

 类似资料:
  • 我试图使用clang和gcc交叉编译一个项目,但在使用时,我发现了一些奇怪的差异,例如。 现在,当涉及NAN时,我期望类型行为,但clang和gcc给出不同的结果: 当我使用它时,_mm_max_ps做了预期的事情。我尝试过使用,,但似乎没有效果。有什么想法可以让编译器之间的行为相似吗? 这里是锁销连接

  • 当一个类具有 constexpr 成员函数并且该成员函数正在 constexpr 上下文中的 l 值对象上求值时,clang 和 gcc 不同意结果是否为 constexpr 值。为什么?是否有既不需要默认可构造性也不需要复制可构造性的解决方法? 当对象按值传递时,两个编译器都会成功编译。 Clang版本trunk,8,7: 和 gcc 版本主干,8.1、7.4:编译没有错误 https://go

  • 为什么无符号右移(逻辑右移)和有符号右移(算术右移)对负数产生相同的结果? Android Studio Logcat输出

  • 下面的例子可以解释我的意思: <代码>自动p=标准::使\u共享 变量是默认初始化的(因此具有垃圾值)还是值初始化的(因此具有零值)?我在GCC 5.2和clang 3.6上进行了测试,前者进行值初始化,后者进行默认初始化。我想知道标准对此有什么规定?在我看来,在这种情况下,现代C肯定应该执行值初始化。

  • 问题内容: 我刚刚注意到了这一点: 为什么这两行的输出不同? 我无法分享确切的数据,但我将尝试提供尽可能多的详细信息: 感谢@jezrael和@ayhan,这就是发生的事情,让我使用@jezael提供的示例: 如果我们看一下第3行: 以及我写条件的方式: 由于符号的优先级高于,因此不带方括号的等效于: 带括号: 我认为用数字说明这个问题要容易一些: 因此,经验教训是:总是加括号!!! 我希望我可以

  • 精明的加法学专家会注意到,它只能加到62位。我在编译器和芯片设计方面的经历告诉我,保留位值黄金。所以我们有两个(设置为零)。 那么这是否意味着: 问题一: ~表示36位移位,包含10位类型Id和其余36位本地Id: #00000000000000000000# ShardID 3429的 二进制=1101 0110 0101 因此(hashedValue>>46)=00000 0 110 1 01