在学习汇编语言的时候,对于左移、算数右移、逻辑右移一般有不同的指令,这几者之间有什么区别和联系?
逻辑右移和算数右移的区别
右移是将数据逐位向低位移动,最低位丢弃,而根据最高位以0填充还是以原始数据的符号位填充,分为逻辑右移和算数右移。以8bit数据为例:
假设有一个数0x83 ,即1000 0011。
1、逻辑右移将各个位向最低位方向移动,最高位补0。0x83逻辑右移1位的结果是0100 0001,即0x41
2、对于算数右移来说,它是将各个位向最低位方向移动,最高位用数据原本的符号位进行填充。对于1000 0011,符号位为1,算数右移一位后,最高位用原本的符号位1来填充,也就是保持符号位不变,结果为1100 0001,即0xc1
逻辑左移=算数左移
以8bit的数据为例,左移1位是将最高位丢弃,其余位向左移动1位,最低位补0,由于最高位符号位被丢弃,因此逻辑左移和算数左移实际是一回事。
下面来看C语言中的移位运算符
int main()
{
char a = 0x83; //a=1000 0011
unsigned char b = 0x83; //b=1000 0011
char c = 0x83; //c=1000 0011
unsigned char d = 0x83; //d=1000 0011
a >>= 1;
b >>= 1;
printf("a=%x b=%#x\n",a,b);
c <<= 1;
d <<= 1;
printf("c=%x d=%#x",c,d);
return 0;
}
输出:
1、根据上面对算数右移和逻辑右移的解释,不难得出:在C语言中,如果定义的是一个有符号的数据类型,例如char型,那么用>>进行右移位,执行的是算数右移,对于无符号数据类型,例如unsigned char型,那么用>>进行右移位,执行的是逻辑右移。(a=ffffffc1是因为printf函数打印char变量时,将其转换为了int型变量,对数据进行了符号位扩展,可以忽略前面的ffffff,就认为实际结果a=0xc1)
2、c和d的结果验证了算数左移和逻辑左移是一回事。
3、一般来说,对于无符号数,左移1位就相当于将这个数扩大两倍,前提是没有发生数据溢出。例如:0x03=0000 0011左移1位后变成 0000 0110 =0x06,。而对于上面的变量d,由于左移后,理论结果是0x83(即十进制131)乘2,等于262,超过了8位无符号数的范围,因此结果并不等于把0x83扩大两倍。
4、对于有符号类型变量,执行算数右移,由于符号位会保持不变,因此结果相当于把这个数除以2,当然如果这个数除以2是有小数出现的(例如5+2=2.5),那么小数部分将会丢失。
5、对于无符号类型变量,执行逻辑右移,结果相当于把这个数除以2,同样会丢失小数部分的结果。