我一直在对位操作进行一些愚蠢的测试,我发现了这个问题。我执行这段代码:
/* ... correct results from i=1 to i=31 ... */
1<<30
mul: 0x40000000 , val: 0x40000000
1<<31
mul: 0x80000000 , val: 0x80000000
1<<32
mul: **0x0** , val: **0x1**
1<<33
mul: **0x0** , val: **0x2**
当然,我知道当我> 31时,会产生溢出。我认为代码的两个部分(way1和way2)应该输出相同的结果。但我得到了这个(最后):
scala> var q = Queue[Int](1)
q: scala.collection.immutable.Queue[Int] = Queue(1)
scala> q :+ 2
res1: scala.collection.immutable.Queue[Int] = Queue(1, 2)
scala> 0 +: q
res2: scala.collection.immutable.Queue[Int] = Queue(0, 1)
为什么,如果两个指令都是左移,程序会产生不同的输出?似乎part way2产生了一个圆转换,但我不知道为什么,我真的认为&#34; mul&#34;总是得到正确的价值。
我在Intel 32bits机器下编译,gcc版本4.4.7
答案 0 :(得分:9)
可能是因为那是未定义的行为?根据{{1}}:
如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。
答案 1 :(得分:2)
如果是
val = (one<<i);
当i
大于或等于32时,行为未定义。
然而,在
的情况下while (temp--)
mul = mul << one;
对于大于32的移位,它将移位零并且结果被定义为零(
)答案 2 :(得分:0)
执行此操作时:
val = (one<<i);
您按i
进行一次左移。如果i
大于31,则会产生undefined behavior,这意味着结果可能会或可能不会达到预期效果。
来自C standard的第6.5.7.3节:
对每个操作数执行整数提升。该 结果的类型是提升的左操作数的类型。 如果 右操作数的值为负或大于或 等于提升的左操作数的宽度,行为是 未定义。强>
但是,当你这样做时:
while (temp--)
mul = mul << one;
你左移1 i
次。这是明确定义的,因此它为您提供了您期望的价值。
此外,当您使用%X
时,您正在使用long
打印%lX
。这也会导致未定义的行为。
答案 3 :(得分:-3)
当我使用-Wall
编译您的代码时,我收到了投诉:
BASH> gcc -Wall left-shift.c
left-shift.c: In function ‘main’:
left-shift.c:21:12: warning: format ‘%X’ expects argument of type ‘unsigned int’, but argument 3 has type ‘long unsigned int’ [-Wformat=]
printf(" \n 1<<%i \n mul: 0x%X , val: 0x%X\n",i, mul, val);
^
left-shift.c:21:12: warning: format ‘%X’ expects argument of type ‘unsigned int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
所以我将printf更改为
printf(" \n 1<<%i \n mul: 0x%lX , val: 0x%lX\n",i, mul, val);
通过此更改,“mul”和“val”显示相同的结果:
1<<30
mul: 0x40000000 , val: 0x40000000
1<<31
mul: 0x80000000 , val: 0x80000000
1<<32
mul: 0x100000000 , val: 0x100000000
1<<33
mul: 0x200000000 , val: 0x200000000
系统信息:
BASH> gcc --version
gcc (Ubuntu 5.3.1-14ubuntu2.1) 5.3.1 20160413
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
BASH> uname -a
Linux bm-pc-ubuntu 4.4.0-24-generic #43-Ubuntu SMP Wed Jun 8 19:27:37 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
BASH> lsb_release --all
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04 LTS
Release: 16.04
Codename: xenial