【问题标题】:what values are allowed for the shift count operation?移位计数操作允许哪些值?
【发布时间】:2017-05-18 18:05:24
【问题描述】:
#include <stdio.h>

int main(void)
{
    unsigned int var=1;
    var = var<<32;
    printf("%u ",var);
} 

此代码产生1 作为其输出。如果我写var = var&lt;&lt;31; 它会产生2147483648

如果我输入var = 12;,然后输入var = var&lt;&lt;32;,它将产生12。我从我的旧教科书中读到,ANSI C 不允许在一次操作中将所有位移出一个值。

当我指示 GCC 执行 var = var&lt;&lt;32; 时,所有主要编译器的行为是否相同(将输入复制粘贴到输出)或者只是 GCC 将粘贴 12 从输入复制到输出????

【问题讨论】:

  • 移动的位数多于数据类型中的位数会导致未定义的行为。因此将 32 位变量移动 32 位(或更多)位是无效的。
  • @Badda 这不是一个有意义的重复,因为 C 在位移方面有很多特定于语言的行为。
  • GCC left shift overflow的可能重复
  • 这是未定义的行为,因为32 超出范围 [0 - 31]。

标签: c bit-shift


【解决方案1】:

C11 6.5.7 移位运算符

如果右操作数的值为负数或大于或 等于提升的左操作数的宽度,行为是 未定义。

这意味着如果在这种情况下移动 32 位或更多位,则没有明确定义的行为。任何事情都可能发生,包括崩溃和奇怪的结果。

我从我的旧教科书中读到,ANSI C 不允许在一次操作中将所有位移出一个值。

这是正确的,您必须执行几个位操作,例如 x&lt;&lt;=16; x&lt;&lt;=16; 以避免未定义的行为。

【讨论】:

  • 如果我输入var = 12; 然后var = var&lt;&lt;32; GCC 输出12。其他主要编译器会给出相同的输出还是完全未定义不管编译器?我知道如果我尝试移动太多位,GCC 被编程为 12。
  • @Mynicks 它是完全未定义的,即使在同一个编译器上也是如此。 GCC 可能今天输出 12 个,明天输出 42 个,后天崩溃并烧毁。这里的关键是你不能依赖未定义的行为来给出某种行为......因此是未定义的。
  • @Mynicks,如果某些东西是 C 语言中的未定义行为,那么它始终是未定义的。 GCC 似乎只是跳过了整个移位操作,因为结果是未定义的(也就是无用的)。
【解决方案2】:

GCC 从字面上说你回答: left shift count &gt;= width of type [-Wshift-count-overflow].

它还取决于您使用的架构。你的问题已经回答here

【讨论】:

    【解决方案3】:

    只是为了更深入一点:

    传统上,C 语言被开发为“便携式汇编程序”。内置操作只是大多数 CPU 实现的操作,它们的语义提供了可移植性的最低公分母。

    几乎每个 CPU 都提供左移和右移操作。但平台在溢出和负数等细节方面存在差异,因此 C 标准未定义极端情况。

    特别是,对于大于寄存器宽度的移位计数,许多 CPU 只使用所需的位数,并截断其余的位。当计数是一个常量时,编译器可能会注意到未定义的行为并将操作作为垃圾丢弃。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-16
      • 2021-09-05
      • 1970-01-01
      • 2021-03-27
      • 2019-11-03
      • 1970-01-01
      • 2020-10-13
      • 1970-01-01
      相关资源
      最近更新 更多