2年前被Boss问了个问题,好像就是变量的倍数如何写,迟疑地问:不是直接乘么?然后结果可想而知,当然当时想要我回答的答案是移位,时过境迁,突然在想,如今这么潮的编译器难道不会优化成移位么
移位<<和>>用于左移和右移,最简单的x<<2将x的值左移两位,右边空出来了两位用0来补,实际上含义就是x乘以4;对于unsigned无符号值进行右移,左边空出来的部分用0来补,对于signed有符号值进行右移,有些机器左边空出来的部分用符号位来补(算术移位),而有些机器左边空出来的部分用0来补(逻辑移位)
具体地说,对于一个位表示为[x(n-1),x(n-2),…,x(0)]的数x,操作x<<k会生成一个值,用位来表示就是[x(n-k-1),x(n-k-2),…,x(0),0,…,0],这里x向左移动了k位,丢弃了高k位,并在低位补了k个0,;而右移x>>k却有两种情况逻辑右移和算术右移,逻辑右移丢弃低k位,在高位补k个0,用位来表示的结果就是[0,…,0,x(n-1),x(n-2),…,x(k)],算术右移丢弃低k位,在高位补k个最高位也就是符号位的值,结果就是[x(n-1),…,x(n-1),x(n-1),x(n-2),…,x(k)],虽然有点奇怪,但是对有符号整数运算有用,而无符号正数只能逻辑右移
x 0110 0011 x 1001 0101 x << 4 0011 0000 x << 4 0101 0000 x >> 4(逻辑) 0000 0110 x >> 4(逻辑) 0000 1001 x >> 4(算术) 0000 0110 x >> 4(算术) 1111 1001
左移就没啥约束,右移如果是无符号的必须是逻辑,有符号既可以算术又可以逻辑,一般来说用得多的还是算术右移
下面有碰到一个警告,假如移位比较大,这里数据有32位,同样移位32,会报警告,而且输出都为0
#include <stdio.h> void main(){ int a = 0xFEAB98CD << 32; int b = 0xFEAB98CD >> 32; unsigned c = 0xFEAB98CDu >> 32; printf("a=%x\n", a); printf("b=%x\n", b); printf("c=%x\n", c); } [lihui@localhost ~]# cc lihui.c lihui.c:4: warning: left shift count >= width of type lihui.c:5: warning: right shift count >= width of type lihui.c:6: warning: right shift count >= width of type [lihui@localhost ~]# ./a.out a=0 b=0 c=0
搜索了一下,有的说法是移位不能超过数据位数,有的说法是移动指令只考虑位移量的低log2w位,也就是位移量通过计算k mod w得到,但是我用的这台机器上并没有这种结果,所以应该尽量保证移位数量比数据位数小
#include <stdio.h> void main(){ int a = 0xFEAB98CD << 28; int b = 0xFEAB98CD >> 30; unsigned c = 0xFEAB98CDu >> 28; printf("a=%x\n", a); printf("b=%x\n", b); printf("c=%x\n", c); } [lihui@localhost ~]# cc lihui.c [lihui@localhost ~]# ./a.out a=d0000000 b=3 c=f