【问题标题】:Unexpected output when executing left-shift by 32 bits执行左移 32 位时出现意外输出
【发布时间】:2014-07-17 17:56:47
【问题描述】:

当我对一个十六进制进行左移时,我得到 -1 作为输出,代码如下:

unsigned int i,j=0;
i= (0xffffffff  << (32-j));
printf("%d",i);

同样,当我将移位值更改为 32 时,输出为 0,但我从编译器收到警告为 (left shift count &gt;= width of type)

unsigned int i,j=32;
i= (0xffffffff  << (32));
printf("%d",i);

我期望两种情况下的结果相同(即 0),但我很困惑为什么在情况 #1 中显示错误的输出,而在情况 #2 中结果是正确的,但编译器会发出警告!

结果在 32 位和 64 位 x86 机器上是相同的。

有人能解释一下上面的结果吗?

【问题讨论】:

  • %d 对于无符号整数是错误的。你需要%u(或%o%x)。
  • @barakmanos- 我将 o/p 设为 -1,当我将格式说明符更改为 %x 时,我将 o/p 设为 ffffffff,其中 j=0、32- j

标签: c


【解决方案1】:

在 32 位整数上留下 32 或更大是未定义的行为。这就是错误所在。

C11 6.5.7 移位运算符

对每个操作数执行整数提升。结果的类型是 提升的左操作数。如果右操作数的值为负数或大于或等于提升的左操作数的宽度,则行为未定义。

【讨论】:

  • 是的 int 在我的机器上是 32 位的,我想知道为什么结果不同?
  • @Sumanta Undefined behavior 的结果是,嗯,未定义,你永远不知道会发生什么。
  • 感谢您的回答
【解决方案2】:

将 32 位变量移位 32 会产生未定义的行为。

这是VS-2013编译器生成的程序集:

    int n = 0;
mov         dword ptr [n],0  
    int a = 0xFFFFFFFF << 32;
mov         dword ptr [a],0  
    int b = 0xFFFFFFFF << (32-n);
mov         ecx,20h  
sub         ecx,dword ptr [n]  
or          eax,0FFFFFFFFh  
shl         eax,cl  
mov         dword ptr [b],eax  

如您所见,事实上发生的是:

  • 当您移动常数值 32 时,编译器只需将结果设置为 0
  • 当您按变量移位时(例如32-nn==0),编译器使用shl

shl 的实际结果取决于该操作在底层架构中的实现。在您的处理器上,它可能需要第二个操作数以 32 为模,因此第一个操作数移动 0。

同样,上面的描述不是由标准规定的,所以它实际上取决于使用的编译器。

【讨论】:

  • HI @barak manos 结果在 32 位和 64 位处理器中是否相同??
  • @Sorcler 如果与 32 位值一起使用 - 也许是,也许不是。这就是 UB 的意义所在——你永远无法知道。你可以测试它,然后你就知道你的 CPU、编译器和编译器选项的组合会如何。
猜你喜欢
  • 1970-01-01
  • 2013-08-11
  • 1970-01-01
  • 2021-11-15
  • 2021-09-28
  • 2018-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多