移位

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

发表回复