【C/C++】关于移位操作的一些自学小结

1、常见的左移右移,以无符号整型为例

可以看到,打印16进制的x值,只有15个f,说明右移4位没问题,高位正常补0。左移同理。
【C/C++】关于移位操作的一些自学小结
其中show方法参考《深入理解计算机系统(第三版)》写的函数,打印目标地址的字节。(我是小端,所以最低有效字节0xff在最前面打印,最高位的0x0f在最后打印。)
同理,如果将x右移63位,会得到只剩一个1,验证也没毛病。
【C/C++】关于移位操作的一些自学小结
然后可以去看看右移63位的汇编的代码:
【C/C++】关于移位操作的一些自学小结
红框圈起来的关键部分:

move %rdi, %rax     将%rdi寄存器的值放到%rax中,%rdi一开始会保存第一个参数,%rax会保存返回值
shrq $63, %rax      将%rax中的值逻辑右移一个立即数63

2、超过数据位数的右移


将右移位数改为64后,会出现“循环位移”的现象(应该是这个名词吧?),下面讲述一下过程。

【C/C++】关于移位操作的一些自学小结
可以看出,当右移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位也就是原数字,可以跑一下代码看看效果。
【C/C++】关于移位操作的一些自学小结
可以看到跟我们的推论结果一致。
个人笔记,如有错误的地方,烦请指正。

上一篇:c语言if语句是如何变成汇编代码的?


下一篇:C语言 使用数组索引与指针索引 在循环中对编译器优化的影响及耗时分析