为什么SHL和SAL相同

来源:互联网 发布:嵌入式软件开发招聘 编辑:程序博客网 时间:2024/04/26 14:29

移位指令简介:

左移:

SAL     OPD, OPS               ; 算术左移,操作数左移,最低位补0,最高位进CFSHL     OPD, OPS               ; 逻辑左移,操作数左移,最低位补0,最高位进CF

右移:

SAR     OPD, OPS               ; 算术右移,操作数右移,最高位不变,最低位进CFSHR     OPD, OPS               ; 逻辑右移,操作数右移,最高位补0,最低位进CF

我们会发现,左移指令 SAL 和 SHL 是进行同样的操作
而右移指令 SAR 和 SHR 进行的是不同的操作


为什么两者会有不同呢?

先来看一段C语言代码:

#include <stdio.h>int main(void){    char n = 64;    unsigned char m = 64;    n = n << 1;    m = m << 1;    printf("n = %d\n", n);    printf("m = %d", m);    return 0;}

运行结果:

n = -128m = 128

我们知道C语言中移位操作常用于快速乘除(左移为乘,右移为除)
但是64为什么左移1位(*2)后变成了一个负数呢?
十进制数64的二进制码为01000000,当它左移后变成10000000
n为一个有符号数,所以10000000就是 -128
m为一个无符号数,所以10000000就是128

对于左移操作:

可以发现,左移操作相当于乘法操作,它是会让操作数变大的,也就是说,它随时存在着溢出的风险

若左移操作保留符号位的话,那么左移会出现越来越小的情况,但是你的本意是让这个数变大这里写图片描述

最后却发现左移后的数变小了,为了规避这种溢出带来的问题,统一了左移操作,也就是说,在左移操作中,寄存器只负责储存这个数(不管是否合乎人意,它只要是个数就行),若没有溢出的时候,则原样存储。所以说左移操作是会改变符号位的(也就是上述C语言的例子)。

对于右移操作:

我们知道右移操作的算术操作是除法,那么在计算机中是肯定让这个数变小的,所以不存在溢出的风险,那么设计者就把是否保留符号位的权力交给了程序编写人员,所以 SAR 和 SHR 是两个不同的操作

这样就能说明SHL和SAL是相同的吗?

对于左移操作:

这里写图片描述

这里写图片描述

可以明显发现,两者对应操作的机器码是完全相同的,由此可以断定, SHL 和 SAL 是不同名的同种操作,下面再来看右移操作。

对于右移操作:

这里写图片描述

这里写图片描述

可以发现他们对应的机器码是不同的,所以 SAR 和 SHR 是两个不同的操作

其他:

关于这两者,维基百科提到:

Logical shifts are best used with unsigned numbers
逻辑移位最好用于无符号数

-

In an arithmetic shift, the spaces are filled in such a way to preserve the sign of the number being slid. For this reason, arithmetic shifts are better suited for signed numbers in two’s complement format
在算术移位中,移位空间被补0或者保留高位(即符号位)的方式处理,因此,算术移位操作更适用于两个有符号数的补码操作


参考:
x86 Assembly - wikibooks
SAL/SAR/SHL/SHR - 移位操作码表


个人浅见,欢迎指正!