将这些位写在纸上,考虑从一端擦除它们,然后在另一端添加更多。与小学不同,乘以 10 时移动小数点。
您所有的 C 函数都将移入零。
所以
x = y << 3;
表示左移三位,右边的新位全为零。左边的三个位进入“位桶”:
x = z >> 2
丢失右边的两位并在左边添加两个零。
您会发现缺少的功能以及 K&R 练习的内容。在现有的处理器类型中,您拥有比 C 或任何其他高级语言更多的转换能力。
您具有旋转功能,其中从一端移位的位在另一端移位。
因此,以这种方式向右旋转一位的数字 0xD 将是 0xE,因为最低有效位是 1,因此将 1101 向右移动,右侧的 1 变为左侧的 1 1110。
有时您会通过ALU中的进位位进行轮换。假设进位位中有一个零,并且您将 0xD 旋转了一位 0 1101 留下 1 0110 a 0x6。再旋转一个,0 1011,你得到一个 0xB 等等。
你为什么要通过你问的进位位旋转?对于更大的数字,假设您有四个位寄存器并且想要进行 8 位移位,假设每个字母都是 bcde fghi 位,其中a
是进位位,另外两组四位是四位寄存器。首先通过进位 e abcd fghi 循环左寄存器,然后通过进位 i abcd efgh 循环右寄存器。很酷;我们刚刚使用 4 位移位函数进行了 8 位移位。
如果您在开始之前清除了进位位(通常有此指令,或者您始终可以执行诸如添加 0+0 之类的操作或其他保证清除该位的操作),您将拥有
我 0bcd efgh
如果您说的是在 64 位数字上运行的 32 位指令集,这与 C 移位函数的作用没有什么不同。
处理器通常具有类似 C 的移位,其中一个零被移入,将 abcd 向左移动 1 得到 bcd0 将 abcd 向右移动 2 得到 00ab。
这给使用现代处理器的年轻人带来了一些问题……想想这些事情,因为他们的处理器都支持整数除法,并且可以在单个时钟周期内运行。早在我们进行除法之前,或者当除法是几十到几百个时钟时,但是移位是一个时钟,您可以使用移位来完成 2 次除法或乘法的所有功率。将数字 0x0D 左移 2 后得到 0b00001101 << 2 = 0b00110100 或 0x34。0xD 是十进制的 13,而 0x34 是十进制的 52。52 是 13 的四倍。四是 2 的 2 次方。移位 2 与乘以 4 相同。
这是双向的;0x34 右移 2 是 0xD,但这就是问题所在。当你得到负数时,将数字减去 4 0xFC,然后将其除以 2。使用 C 0xFC >> 1 将给出 0x7E,但 0x7E 是十进制的 +126。-4/2 = 126 怎么算?
问题是 C 在零处移动。您会发现某些处理器具有与逻辑移位不同的算术移位。算术移位保持最高位,所以如果你使用一个有符号数,比如 0bQWER,并且你算术右移一位,你会得到 0bQQwe。最高位都移动到下一位并保持在原来的位置。
再次移位 0bQQQW,以此类推。现在算术左移将移入零而不是最低有效位,因此 0bQWER 左移一位是 0bWER0。这是有道理的。-4 左移一位是 0xF8,即 -8,-4 乘以 2 是 -8,所以是正确的。
所以你会发现有些处理器只有算术右移,而没有左移。有些允许你指定一个 asl,但是当他们组装它时,用 lsl(逻辑左移)替换它,谁知道有些可能实际上有一个单独的操作码,即使它是相同的功能。我假设可能有一些有 asl 和 asr 和 lsr,但没有 lsl。
只需使用纸和铅笔并弄清楚事情。从实数作为例子开始,然后再抽象。想0x1234
向右旋转一点,比方说?
0001001000110100 write out the bits
x0001001000110100 shift right one
0000100100011010 because this is a rotate fill in the new bit with the bit that fell off on the prior operation
现在想右移两位
0000100100011010
xx0000100100011010
1000001001000110
我将如何在 C 中进行一次旋转?
unsigned int rotate_right_one ( unsigned int x )
{
unsigned int y;
y = x & 1; // Save the bit that is about to fall off the right
x >> = 1; // Logical rotate one bit
x |= y<<31; // This assumes that unsigned int is 32 bits.
return(x);
}
要旋转更多,您可以简单地多次调用此函数,或者考虑掩码并在上方移动,以及它如何工作超过一位。
另请注意,某些处理器只有一种旋转功能。例如,想想这个。我有一个四位寄存器,我旋转 5 位。我能得到什么?
abcd
bcda first rotate
cdab second
dabc third
abcd fourth
bcda fifth
单向左旋转是什么样的?
abcd
bcda one bit left.
四位寄存器上的右五与左一相同 5-4=1。与 asl 一样,一些处理器允许您对操作进行编码,但汇编器使用 nbits-shift 作为旋转量,用另一个旋转替换该操作。
对于某些人来说,逻辑位运算就像指针一样难以理解,但它是基础,如果您学习并使用它,您将领先于您的竞争对手或您周围的人。
这是一个计算某个变量中位数的示例:
for(count=0, r=1; r; r<<=1)
if(r&some_variable)
count++;
理解那行代码,你就可以很好地学习 C 和逻辑位操作。