A more efficient general approach would be to iterate over the bits, but only process the number of bits in the mask, removing the if (mask & (1<<i)) test from your loop and looping only 7 times instead of 16 for your example mask. At each iteration of the loop, find the rightmost bit of the mask , check it with n, set the corresponding bit to the result, and then remove it from the mask.
int mask = 0x10f3; int n = 0xda4d; int result = 0; int m = mask, pos = 1; while(m != 0) { // find rightmost bit in m: int bit = m & -m; if (n & bit) result |= pos; pos <<= 1; m &= ~bit; // remove the rightmost bit from m } printf("%04x %04x %04x\n", mask, n, result);
Output:
10f3 da4d 0051
Or perhaps less readable, but without the bit temp variable:
if (n & -m & m) result |= pos; pos <<= 1; m &= m-1;
How it works? First, think about why m &= m-1 clears the rightmost (least significant) bit of the set. Your (non-zero) mask m will consist of a certain number of bits, and then 1 in the least significant place, then zero or more 0s:
eg:
xxxxxxxxxxxx1000
Subtraction 1 gives:
xxxxxxxxxxxx0111
Thus, all bits exceeding the least significant bit will be unchanged (therefore, combining them does not leave them unchanged), the least significant set bit changes from 1 to 0, and the least significant bits all 0 s in advance, therefore, And they all leave them unchanged . Pure result: the bit of the least significant digit is cleared, and the rest of the word remains the same.
To understand why m and -m give the least significant set bit, combine the above with the knowledge that in addition 2s, -x = ~(x-1)