c中的左移位

时间:2016-06-21 15:46:17

标签: c bit-shift

我一直在对位操作进行一些愚蠢的测试,我发现了这个问题。我执行这段代码:

 /* ... 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

4 个答案:

答案 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