按类型宽度移位不会返回零

时间:2016-07-03 13:11:39

标签: c bit-shift

对于简单的混淆分配,我需要移动unsigned int直到它变为零。

unsigned int a = 12;
a <<= sizeof(a) * 8;
printf("%u", a);

我使用gcc test.c -o bin编译它,GCC警告:

warning: left shift count >= width of type [-Wshift-count-overflow]

当我执行它时,它返回12。但毫无疑问,它应该是0。 GCC是否忽略了编译那行代码?或者我错过了什么?

1 个答案:

答案 0 :(得分:3)

这是未定义的行为。

  

在任何情况下,如果右操作数的值[&lt;&lt;或&gt;&gt;]为负数或大于或等于提升左操作数中的位数,行为未定义。

(引自http://en.cppreference.com/w/cpp/language/operator_arithmetic

此外,文章说:

  • 无符号溢出和下溢是明确定义的,额外的位被截断。
  • <<的带符号溢出未定义。 (自从C ++ 14以来,如果结果值可以用左类型的无符号版本表示,那么它是明确定义的。然后将tesult转换回签名。)
  • 应用于签名否定的
  • >>是实现定义的。 (Cppreference说,在大多数架构中,它会复制最左边的位。)
  • <<申请签署的否定文件未定义。

这些规则对于C和C ++是相同的。以下是C11标准的相关部分:

6.5.7按位移位运算符

  
      
  1. 对每个操作数执行整数提升。结果的类型是   升级的左操作数。如果右操作数的值为负数或
  2.   
  3. E1的结果&lt;&lt; E2是E1左移E2位位置;腾出的位充满了   零。如果E1具有无符号类型,则结果的值为E1×2E2,模数减少   比结果类型中可表示的最大值多一个。如果E1有签名   类型和非负值,E1×2E2在结果类型中可表示,那就是   结果价值;否则,行为未定义。
  4.   
  5. E1的结果&gt; E2是E1右移E2位位置。如果E1具有无符号类型   或者如果E1具有带符号类型和非负值,则结果的值为积分   E1 / 2E2商的一部分。如果E1有签名类型和负值,则   结果值是实现定义的。
  6.