1、常见的左移右移,以无符号整型为例
可以看到,打印16进制的x值,只有15个f,说明右移4位没问题,高位正常补0。左移同理。
其中show方法参考《深入理解计算机系统(第三版)》写的函数,打印目标地址的字节。(我是小端,所以最低有效字节0xff在最前面打印,最高位的0x0f在最后打印。)
同理,如果将x右移63位,会得到只剩一个1,验证也没毛病。
然后可以去看看右移63位的汇编的代码:
红框圈起来的关键部分:
move %rdi, %rax 将%rdi寄存器的值放到%rax中,%rdi一开始会保存第一个参数,%rax会保存返回值
shrq $63, %rax 将%rax中的值逻辑右移一个立即数63
2、超过数据位数的右移
将右移位数改为64后,会出现“循环位移”的现象(应该是这个名词吧?),下面讲述一下过程。
可以看出,当右移64位时,会警告右移数>=类型宽度,但是依然可以编译,得到右边的汇编代码。
movq %rdi, %rax 同上,第一个参数放到返回值
movl $64, %ecx 将立即数放到%ecx中
shrq %cl, %rax 将%rax中的值右移%cl中的值的位数
这边比较难理解的是第二三句,其中有两个点注意到了就不难了。
1、(参照《深入理解计算机系统(第三版)》131页移位操作)位移量可以是一个立即数,或者放在单字节寄存器%cl中(只允许这个特定的寄存器作为操作数)x86-64中,移位操作对w位长的数据值进行操作,位移量由%cl寄存器的低m位决定,这里2^m=w,高位被忽略。
2、%rcx是一个64位寄存器,而他的低32位计为%ecx,低16位计为%cx,低8位计为%cl。所以此处其实就是将64拷贝到%rcx的低32位上,并将高位清0。
综上两个点,这里uint64_t是64位无符号整型,2^6=64,m=6,因此由%cl中的值(64=1000000二进制),只能使用其中的6位000000位移,右移0位也就是原数字,可以跑一下代码看看效果。
可以看到跟我们的推论结果一致。
个人笔记,如有错误的地方,烦请指正。