如何从一个整数中复制2位到另一个整数?

5
我有两个无符号整数:abb 是一个无符号整数指针)。我想复制a的第8和第9位到b的第2和第3位(所有索引均从0开始计算)。
这是我的做法:
 bool secondBit =  (a & (1 << 8) ) ;
 bool thirdBit =   (a & (1 << 9) ) ;

 if (secondBit) {
     *b |= (1u << 2);
 }
 if (thirdBit) {
     *b |= (1u << 3);

提醒: b 是一个无符号整数指针。

有没有更好的方法来做这件事?


1
https://dev59.com/hW3Xa4cB1Zd3GeqPdlu3 - Andy897
像这样的问题,字节序是否重要? - Logan Murphy
a 不是指针,只是一个整数。 - brainydexter
请注意,如果 *b 中的位已经被设置,则此操作实际上不会重置该位。如果这是您的意图,那么我认为您的代码比顶部答案更清晰。 - M.M
4个回答

13

清除*b相关位并将其设置为您从a中想要的位:

*b = (*b & ~0xC) | ((a & 0x300) >> 6);

// This is the 'not' of 00001100, in other words, 11110011
~0xC;

// This zeros the bits of *b that you do not want (b being a pointer)
*b & ~0xC;   // *b & 11110011

//This clears all of a <b>except</b> the bits that you want
a & 0x300;

// Shift the result into the location that you want to set in *b (bits 2 and 3)   
((a & 0x300) >> 6);

// Now set the bits into *b without changing any other bits in *b
*b = (*b & ~0xC) | ((a & 0x300) >> 6);

1
@brainydexter (1) 0xC12,用二进制表示为...0 1100,按位取反~后得到...1 0011。将*b与其进行按位与操作,可以得到一个已清除第2和第3位的*b。**(2)** 0x3000x100 + 0x200,它们分别是2的8次方和2的9次方,意味着它们代表第8和第9位。将a与其进行按位与操作,可以得到只有第8和第9位的a。将其向右移动6位,可以使这些位位于第2和第3位。**(3)** 将这两个结果进行按位或操作即可得到所需的结果,然后将其赋值给*b - Utkan Gezer
@brainydexter 是的,它会,但我们已经在|的左侧拥有了整个*b(不包括第二位和第三位)。 |将来自a的2位添加到其中。 - Utkan Gezer
1
+1,但我会先移位a,然后再应用掩码(*b = (*b & ~0xC) | ((a >> 6) & 0xC)),因为你在OR的两侧都有相同的掩码(除了反转)。 - pat
pat: 是的,那样可能会更清晰。我写的方式只是我思考位掩码的结果(当我读到“位8和9”时,我想到的是“0x300”)。@ThoAppelsin:编辑得很好。 - Michael
@Michael 这是一个离题的评论。我看到你回答了许多关于OpenSL ES的问题,这就是为什么我来找你的原因。你能否回答我的这个问题? https://dev59.com/XH3aa4cB1Zd3GeqPd399 - Reaz Murshed
显示剩余5条评论

2

根据你对"更好"的定义 :)

但是,C++中有std::bitset类。也许它通过提供一个不那么容易出错的接口来满足您的需求。


我不知道std :: bitset的实现,但它可能比“掩码、移位、取消掩码”方法更低效。 - Jabberwocky
更高效可能吧。我不确定,我还没有测量:) 实际应用中它的实际差异很小,很难在没有任何上下文的情况下确定。 - Christian Hackl

0
在给定的代码中,它没有复制位 - 它只是对它们进行或运算。它应该这样做吗?
*b &= ~0xC0;

首先?然后

*b |= ((a >> 6) & 0xC0);

这不正确。第一行将清零*b的所有位,除了位0和位1。你的意思是要使用~0xC进行AND运算,只清零位2和位3。通常,插入掩码是dst = (dst & ~mask) | (src & mask),其中src的位已经处于正确的位置,而mask对于我们希望插入的每个位都有一个1,并且对于我们希望保留的每个位都有一个0 - pat

0
这是一种更详细的创建你所需结果的方式,并附上测试操作的代码。
#include <stdio.h>

void printBits(int n)
{
   int i = 31;
   char bits[32];
   for ( ; i >= 0; --i, n /= 2 )
   {
      bits[i]= n % 2;
   }

   for ( i = 0; i < 32; ++i )
   {
      printf("%d", bits[i]);
      if ( (i+1)%8 == 0 )
      {
         putchar(' ');
      }
   }
}

int foo(int n1, int n2)
{
   // copy 8th and 9th bit of n1 to 2nd and 3rd bit of n2 
   // (all indices are 0 based).

   // Extract the 8th and 9th bits of n1
   int k1 = 0x00000300;
   int r1 = n1 & k1;

   // Clear the 2nd and 3rd bits of n2.
   int k2 = 0xFFFFFFF9;
   int r2 = n2 & k2;

   // Move the 8th and 9th bits of n1 by 6 to the right
   // to put them in 2nd and 3rd places.
   // Construct the result and return.
   return (r1 >> 6) | r2;
}

int main(int argc, char** argv)
{
   int n1 = atoi(argv[1]);
   int n2 = atoi(argv[2]);

   printf("Input n1: ");
   printBits(n1);
   printf("\n");

   printf("Input n2: ");
   printBits(n2);
   printf("\n");

   int n3 = foo(n1, n2);

   printf("Result  : ");
   printBits(n3);
   printf("\n");
}

示例输出:

./test-19 251282 85
输入 n1: 00000000 00000011 11010101 10010010
输入 n2: 00000000 00000000 00000000 10000000
结果:00000000 00000000 00000000 10000100

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接