5

I have two unsigned int numbers: a and b (b is an unsigned int pointer). I want to copy 8th and 9th bit of a to 2nd and 3rd bit of b(all indices are 0 based).

This is how I am doing it:

 bool secondBit =  (a & (1 << 8) ) ;
 bool thirdBit =   (a & (1 << 9) ) ;

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

Reminder: b is an unsigned int pointer.

Is there a better way of doing this ?

Utkan Gezer
  • 3,009
  • 2
  • 16
  • 29
brainydexter
  • 19,826
  • 28
  • 77
  • 115

4 Answers4

13

Clear the relevant bits of *b and set them to the bits you want from 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 except 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);
Michael
  • 57,169
  • 9
  • 80
  • 125
  • I'm trying to wrap my head around what you wrote. Can you explain, what are we doing here ? – brainydexter Mar 21 '14 at 17:42
  • 1
    @brainydexter **(1)** `0xC` is `12`, which is represented as `...0 1100` in binary, bitwise negation `~` of which is `...1 0011`. And'ing `*b` with that gives you a `*b` with its 2nd and 3rd bits cleared. **(2)** `0x300` is `0x100 + 0x200`, which are 8th and 9th powers of 2, meaning that they represent the 8th and 9th bits. And'ing `a` with that gives you an `a` with only 8th and 9th bits. Shifting that 6 bits towards right, makes those bits to get located at 2nd and 3rd bits. **(3)** Or'ing those two result in what you want, so we assign (or he assigns) that to `*b` – Utkan Gezer Mar 21 '14 at 17:47
  • @brainydexter no problem bro... But god, I hate it when I see a stale direct answer like this, getting so much up-votes... – Utkan Gezer Mar 21 '14 at 17:52
  • Actually I have a question about your point 3. I understand Or'ing those two, gets the bits if they are set or not. When we assign those two bits to `*b`, will that not not overwrite the entire value of `*b` ? – brainydexter Mar 21 '14 at 17:54
  • @brainydexter Yes, it will, but we already had the entire `*b` (with 2nd and 3rd bits excluded) in our hands on the left hand side of the `|`. `|` adds the 2 bits from `a` to that. – Utkan Gezer Mar 21 '14 at 17:56
  • 1
    +1, but I would have shifted `a` first, and then applied the mask (`*b = (*b & ~0xC) | ((a >> 6) & 0xC)`) since you have the same mask (modulo the invert) on both sides of the OR. – pat Mar 21 '14 at 18:04
  • pat: yeah, that probably would be clearer. The way I wrote it is just a result of how I think of bitmasks (when I read "bits 8 and 9" I think "0x300"). @ThoAppelsin: Nice edit. – Michael Mar 21 '14 at 18:40
  • @Michael Please, credits to [sabbahillel](http://stackoverflow.com/revisions/22565735/2) for revision #2, I just fixed some minor issues, possibly were just typos. – Utkan Gezer Mar 21 '14 at 18:44
  • @Michael This is an off topic comment. I saw you've answered many questions regarding OpenSL ES and that's why I'm knocking. Can you please answer to this question of mine? http://stackoverflow.com/questions/22342040/voice-communication-at-8khz-sampling-rate-for-all-android-device-using-opensl – Reaz Murshed Mar 23 '14 at 02:29
2

Depends on your definition of "better" :)

But, well, there is the std::bitset class in C++. Perhaps it suits your needs by offering a less error-prone interface.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • I don't know the implementation of std::bitset, but it is probably less efficient then the "mask, shift, unmask" approach. – Jabberwocky Mar 21 '14 at 17:44
  • Or more efficient. I don't know, I've not measured :) Chances are the actual difference in his real application is too small to be measured. Hard to tell without any context, really. – Christian Hackl Mar 21 '14 at 17:47
0

In the given code, it does not copy the bits - it just ors them. Should it be doing

*b &= ~0xC0;

first? Then

*b |= ((a >> 6) & 0xC0);
cup
  • 7,589
  • 4
  • 19
  • 42
  • This is not correct. The first line will zero all bits of `*b` *except* bit-0 and bit-1. You meant to AND with `~0xC` to zero only bit-2 and bit-3. In general, insert under mask is `dst = (dst & ~mask) | (src & mask)` where the bits of `src` are already in the correct position, and `mask` has a `1` for every bit we wish to insert, and a `0` for every bit we wish to preserve. – pat Mar 21 '14 at 18:02
0

Here's a more verbose way of creating the result you are looking for and code to test the operation.

#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");
}

Sample output:

./test-19 251282 85
Input n1: 00000000 00000011 11010101 10010010
Input n2: 00000000 00000000 00000000 10000000
Result  : 00000000 00000000 00000000 10000100
R Sahu
  • 204,454
  • 14
  • 159
  • 270