我在哪里可以找到C的位移指南?

时间:2009-01-14 15:01:47

标签: c bit-shift

我看过What are bitwise shift (bit-shift) operators and how do they work?但我仍然觉得比特移位的概念很难理解。

有人能指出我在C语言中进行比特转换的更基本指南的方向。我希望它会很长,因为它需要涵盖整个主题。

我真的不明白,但我想学习它,所以任何帮助都会受到赞赏。

我正在学习k& r,这就是这个,所以我可以做练习。我理解基础知识,但我仍然无法做正确的位移操作。

编辑这里是来自K& R的那些让我难过的人

练习2-6:写一个函数setbits(x,p,n,y),它返回x,其中n位位于p位置,位于y的最右边n位,其他位保持不变。

练习2-7:写一个函数invert(x,p,n),它返回x,其中n位从poisiton p开始反转(即1变为0,反之亦然),其他不变。

练习2-8:写一个函数rightrot(x,n),它返回整数x的值,向右旋转n位位置

练习2-9:在二进制补码系统中,x& =(x-1)删除x中最右边的1位。解释原因,使用此观察来编写更快的bitcount版本

这些是来自k& R(c编程语言)书籍的练习,它是最好的c书,但我无法理解比特档,所以我在这些练习中遇到了问题。

12 个答案:

答案 0 :(得分:7)

比特移位只不过是字面意思意味着:向左或向右移动给定序列中的所有比特。

您必须记住的是,每个十进制数字(如6,7,3,2)都表示为计算机内存中的一系列位。所以如果你在一段C代码中找到类似的东西:

(7 >> 1)

这意味着7的基础二进制表示中的位将向右移位1个位置。

我认为您引用的链接中的解释非常明确。也许你自己在纸上写下一系列的比特并按引用的链接操纵它们可以提供帮助。

或者您可能还不太了解计算机如何在内部处理数字。在这种情况下,在学习位移之前,您需要阅读相关内容。

答案 1 :(得分:4)

您需要在工具包中使用更多工具来回答这些问题,而不是转移。

我认为你需要开始非常基本的数字如何用二进制表示。然后,您将考虑如何设置和清除该数字中的特定位或同时清除一组位。您需要知道如何测试以查看是否设置了某组位和屏蔽。您必须能够使用按位运算符和/或/ xor / inversion / etc运算符执行上述所有操作。然后你会想知道移位 - 左右移动特定数量的空格。你会想知道“空”的位会发生什么。是填充1还是0?什么时候填充1或0?

谷歌搜索“按位操作教程”似乎已经提出了一些有希望的结果。但是这里有一些基础知识来测试自己,以确保你理解

// 1234 in hex, you understand this is not 1234 in decimal? Do you understand
// how specifying in hex makes it easier to think about the binary representation?
unsigned short i = 0x1234; 
// flip all the bits in 0x1234
printf("%04x", ~i);

// Test - Is the most significant bit set?
// mask is a binary number with the most significant bit set. Do
// you understand why this is so?
unsigned short mask = 0x8000;   
if ((mask & i) == mask)
{
    printf("bit set!");
}
else 
{
    printf("bit cleared!");
}

// set the most significant bit
i = i | mask;
printf("Set the MSB of i, check it out: %i\n", i)

// set the second most significant bit
// Do you see how by shifting mask right one it becomes the next most significant bit?
i = i | (mask >> 1);

祝你好运!

答案 2 :(得分:1)

答案 3 :(得分:1)

以2-6为例,我使用了值17,1,4,1 所以:

x = 17或10001

p = 4

n = 3

y = 15或01111

使用我的示例数字我们需要做的是从y(111)取三个ls位并从位置4开始将它们插入x。这将给出11111或31.我们需要清除3位x从位置4开始,清除y中的所有位,除了最右边的3位,将它们移动到位置4并将这两个值相加。

1st:将所有1移位到左边n个位置〜0<< n = 1111111111111000

第二:将所有的位置放在最右边的n个位置〜(~0 <&lt; n)= 0000000000000111

第3步:将这n个位移到位置p,并从位置p开始将n位设置为零。      〜(〜(〜0 <&lt; n)&lt;&lt;(p-n))= 1111111111110001

第4次:这个掩码用x来清除位置p = 10001的x位n

(我相信每个人都意识到我们所做的就是回到我们的起始号码,  但我们必须这样做才能告诉程序我们想要从哪个位置开始,以及  我们想要使用多少位。如果p为6且n为4,该怎么办?)

接下来清除y中的所有位,除了最右边的n位:

第1:〜(〜0 <&lt; n)将所有的一个放在最右边的n个位置。 0000000000000111

第二名:y&amp; 〜(〜0&lt;&lt; n)选择y 0000000000000111的最右边n位

第3 :( y&amp;〜(~0 <&lt; n))&lt;&lt; (p-n)将n位y放在位置p 0000000000001110处 最后还是两个结果一起

0000000000010001 = 17

0000000000001110 = 7 OR =

0000000000011111 = 31

结果变为:

  

返回x&amp; 〜(〜(~0 <&lt; n)&lt;&lt;(p-n))| (y&amp;〜(~0 <&lt; n))&lt;&lt; (P-N);

如果这很难读,我很抱歉。我的格式化能力有点受限。 (我确信这是我的错)我希望这有帮助,我一直坚持这个特定的练习很长一段时间,最后在看了这个线程之后,今天想出了这个解决方案,所以我想我会发布正确的答案,以及解释为什么它是正确的答案,这是我发现在我看到的许多答案中缺乏的东西。

答案 4 :(得分:0)

您链接的指南非常好。什么是你不了解的位移?

我不知道K&amp; R是什么,所以我无法帮助你。

你能否更具体地回答这个问题,我可以编辑以更具体地回答问题。

答案 5 :(得分:0)

如果你有钱(和时间),请抓一份Hackers Delight。它可能是最好的位移指南。它将通过简单的移位(和其他操作技术)一直通过格雷码和更多......

答案 6 :(得分:0)

让我们进行一次练习,获取样本。

  

练习2-6:编写一个函数   返回x的setbits(x,p,n,y)   从位置开始的n位   p设置为y的最右边n位,   保持其他位不变。

让我们保持最低有效位是位0(位于0位置)

这是伪代码:

  1. 将位p移动到x中的p + n到位置0到n。这就是你右移的地方。
  2. 准备一个位掩码,将位n从最高位变为0。您可以使用查找数组(例如,对于n = 8为0xFF,对于7为0x7F等等),或者您可以在循环中使用设置位0和lef-shifting的组合。
  3. 使用&amp;将位掩码应用于x 。我们在x中不关心的所有位现在都是0
  4. 反转位掩码。我们现在在高端有一堆1,在低端有一堆0。我们想要更改的位在位掩码中都有0。
  5. 使用&amp;将位掩码应用于y 。我们将用x中的位替换的y中的所有位现在都设置为0,并且我们不想更改的位不变。
  6. 通过使用|组合x和y来设置我们想要在y中更改的位。这是至关重要的一点 - 用笔和纸来回顾正在发生的事情。在(3)中设置为0的x中的位不会影响y中的相应位。 x中不受(3)影响的位将与y中的0结合(因为步骤5为0),将结果位设置为x中的值。

答案 7 :(得分:0)

请记住,几乎所有这些练习都有一个简单的解决方案,可以使用函数int IsBitSet(int i,int n)编写; int SetBit(int i,int n);和&lt;&lt;的组合和&gt;&gt;。简单的解决方案几乎都是最糟糕的情况,但更容易实现和阅读。这有点像在增量方面的加法或加法方面实现乘法。

答案 8 :(得分:0)

让我们尝试2-6,让您体验位操作的工作原理,然后看看它是否有意义。

int setbits( int x, int p, int n, int y )
{
    int bitmask = ~0, y_right = 0; 

    /* Ok, first let's get y's rightmost bits.
     * Take our bitmask, shift it left by n bits, leaving the least significant
     * n bits as 0. Then, flip the bitmask so the rightmost n bits become 1, and the
     * leftmost n bits become 0.
     *
     * Then, AND this bitmask with y, to yield y's n rightmost bits.
     */
    bitmask = ~( bitmask << n );
    y_right = bitmask & y;

    /*
     * Ok, now let's use y_right as our bitmask for x.
     * Shift y_right to the left to *begin* at position p.
     */
     y_right <<= p - n;
     x |= y_right;

     return x;
}

注意:上面的内容可能完全不正确,因为我没有测试过,但它应该给你一个不错的想法。

答案 9 :(得分:0)

这里有关于堆栈溢出的位运算符的很好的介绍:Here

答案 10 :(得分:0)

答案 11 :(得分:0)

这是我在AVRFreaks找到一些时间的基本指南。 这将向您展示基础知识,然后您可以继续学习其他教程。