本文主要是介绍为什么SHL和SAL相同,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 1 移位指令简介
- 1.1 左移
- 1.2 右移
- 2 为什么两者会有不同呢?
- 2.1 对于左移操作
- 2.2 对于右移操作
- 2.3 这样就能说明SHL和SAL是相同的吗?
- 2.3.1 对于左移操作:
- 2.3.2 对于右移操作
- 3 其他
1 移位指令简介
1.1 左移
SAL OPD, OPS ; 算术左移,操作数左移,最低位补0,最高位进CF
SHL OPD, OPS ; 逻辑左移,操作数左移,最低位补0,最高位进CF
1.2 右移
SAR OPD, OPS ; 算术右移,操作数右移,最高位不变,最低位进CF
SHR OPD, OPS ; 逻辑右移,操作数右移,最高位补0,最低位进CF
我们会发现,左移指令 SAL
和SHL
是进行同样的操作
而右移指令 SAR
和SHR
进行的是不同的操作
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 对于右移操作
我们知道右移操作的算术操作是除法,那么在计算机中是肯定让这个数变小的,所以不存在溢出的风险,那么设计者就把是否保留符号位的权力交给了程序编写人员,所以 SAR
和SHR
是两个不同的操作。
2.3 这样就能说明SHL和SAL是相同的吗?
2.3.1 对于左移操作:
可以明显发现,两者对应操作的机器码是完全相同的,由此可以断定, SHL
和 SAL
是不同名的同种操作,下面再来看右移操作。
2.3.2 对于右移操作
可以发现他们对应的机器码是不同的,所以 SAR
和 SHR
是两个不同的操作。
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 - 移位操作码表
这篇关于为什么SHL和SAL相同的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!