为什么SHL和SAL相同

1 移位指令简介

1.1 左移

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

1.2 右移

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

我们会发现,左移指令 SALSHL是进行同样的操作
而右移指令 SARSHR 进行的是不同的操作

2 为什么两者会有不同呢?

先来看一段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 = -128
m = 128

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

2.1 对于左移操作

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

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

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

2.2 对于右移操作

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

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

2.3.1 对于左移操作:

这里写图片描述

这里写图片描述

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

2.3.2 对于右移操作

这里写图片描述

这里写图片描述

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

3 其他

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

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 - 移位操作码表


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值