[英]Left shift bits in c
我一直在做一些关于位操作的愚蠢测试,我发现了这个问题。 我执行这段代码:
int main(){
unsigned int i;
for (i=1; i<34; i++)
{
unsigned long temp = i;
unsigned long mul = 1;
unsigned long val;
unsigned long one = 1;
// Way 1
while (temp--)
mul = mul << one;
// Way 2
val = (one<<i);
printf(" \n 1<<%i \n mul: 0x%X , val: 0x%X\n",i, mul, val);
}
}
当然,我知道当我> 31时,会产生溢出。 我认为代码的两个部分(way1和way2)应该输出相同的结果。 但我得到了这个(最后):
/* ... 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**
为什么,如果两个指令都是左移,程序会产生不同的输出? 似乎part way2产生了一个圆转换,但我不知道为什么,我真的认为“mul”总是得到正确的值。
我在Intel 32bits机器下编译,gcc版本4.4.7
可能是因为那是未定义的行为? 根据§6.5.7
:
如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。
的情况下
val = (one<<i);
当i
大于或等于32时,行为是未定义的。
但是,如果是的话
while (temp--)
mul = mul << one;
对于超过32的移位,它将移零并且结果被定义(零)。
当我用-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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.