简体   繁体   中英

Swapping bits in an integer in C, can you explain this function to me?

I want to write a function that receives an unsigned char and swaps between bit 2 and bit 4 and returns the new number.

I am not allowed to use if statement.

So I found this function, among other functions, but this was the most simple one to understand (or try to understand).

All other functions involve XOR which I don't really understand to be honest.

unsigned char SwapBits(unsigned char num)
{
    
    unsigned char mask2 = ( num & 0x04 ) << 2;
    
    unsigned char mask4 = ( num & 0x10 ) >> 2;
    
    unsigned char mask  = mask3 | mask5 ;
    
    return ( num & 0xeb ) | mask;


}    

Can someone explain me what happens here and most important, why? Why AND is required here and why with hex address ? Why should I AND with 0xeb (255)? I know that's the range of char but why should I do that.

In short, I know how to read codes. I understand this code, but I don't understand the purpose of each line.

Thanks.

First, the usual convention is that bits are numbered starting from 0 for the least significant bit and counting up. In this case, you have an 8-bit value, so the bits go from 0 on the right up to 7 on the left.

The function you posted still isn't quite right, but I think I see where you (it) was going with it. Here are the steps it's doing:

  1. Pull out bit 2 (which is 3rd from the right) using a mask
  2. Pull out bit 4 (which is 5th from the right) using a mask
  3. Shift bit 2 left 2 positions so it's now in bit 4's original position
  4. Shift bit 4 right 2 positions so it's now in bit 2's original position
  5. Join these two bits together into one value that is now bits 2 and 4 swapped
  6. Mask out (erase using &) only bits 2 and 4 from the original value
  7. Join in (insert using |) the new swapped bits 2 and 4 to complete the transformation

I have rewritten the function to show each step one at a time to help make it clearer. In the original function or other examples you find, you'll see many of these steps all happen together in the same statement.

unsigned char SwapBits(unsigned char num)
{
    // preserve only bit 2
    unsigned char bit2 = num & 0x04;
    
    // preserve only bit 4
    unsigned char bit4 = num & 0x10;
    
    // move bit 2 left to bit 4 position
    unsigned char bit2_moved = bit2 << 2;
    
    // move bit 4 right to bit 2 position
    unsigned char bit4_moved = bit4 >> 2;
    
    // put the two moved bits together into one swapped value
    unsigned char swapped_bits  = bit2_moved | bit4_moved;
    
    // clear bits 2 and 4 from the original value
    unsigned char num_with_swapped_bits_cleared = num & ~0x14;
    
    // put swapped bits back into the original value to complete the swap
    return num_with_swapped_bits_cleared | swapped_bits;
} 

The second to last step num & ~0x14 probably needs some explanation. Since we want to save all the original bits except for bits 2 and 4, we mask out (erase) only the bits we're changing and leave all the others alone. The bits we want to erase are in positions 2 and 4, which are the 1s in the mask 0x14. So we do a complement (~) on 0x14 to turn it into all 1s everywhere except for 0s in bits 2 and 4. Then we AND this value with the original number, which has the effect of changing bits 2 and 4 to 0 while leaving all the others alone. This allows us to OR in the new swapped bits as the final step to complete the process.

You have to read about binary representation of number

unsigned char SwapBits(unsigned char num)
{
// let say that [num] = 46, it means that is is represented 0b00101110

    unsigned char mask2 = ( num & 0x04 ) << 2;
// now, another byte named mask2 will be equal to:
// 0b00101110 num
// 0b00000100 0x04
//     . .1.  mask2 = 4. Here the & failed with . as BOTH ([and]) bits need to be set. Basically it keeps only numbers that have the 3rd bit set

    unsigned char mask4 = ( num & 0x10 ) >> 2;
// 0b00101110 num
// 0b00010000 0x10 -> means 16 in decimal or 0b10000 in binary or 2^4 (the power is also the number of trailing 0 after the bit set)
// 0b00.....0 mask4 = 0, all bits failed to be both set

    unsigned char mask  = mask3 | mask5 ;
// mask will take bits at each position if either set by mask3 [or] mask5 so:
// 0b1001 mask3
// 0boo11 mask4
// 0b1011 mask

    return ( num & 0xeb ) | mask; // you now know how it works ;) solve this one. PS: operation between Brackets have priority
}    

If you are interested to learn the basics of bitwise operators you can take a look at this introduction .

After you build confidence you can try solving algorithms using only bitwise operators, where you will explore even deeper bitwise operations and see its impact on the runtime;)

I also recommend reading Bit Twiddling Hacks , Oldies but Goodies!

b = ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32; // reverse your byte!

Simple function to understand swap of bit 3 and 5:

if you want to swap bit index 3 and bit index 5, then you have to do the following:

int n = 0b100010
int mask = 0b100000 // keep bit index 5 (starting from index 0)
int mask2 = 0b1000 // keep bit index 3

n = (n & mask) >> 2 | (n & mask2) << 2 | (n & 0b010111); 

// (n & mask) >> 2
// the mask index 5 is decrease by 2 position (>>2) and brings along with it the bit located at index 5 that it had captured in n thanks to the AND operand. 

// | (n & mask2) << 2
// mask2 is increased by 2 index and set it to 0 since n didn't have a bit set at index 3 originally.

// | (n & 0b010111); // bits 0 1 2 and 4 are preserved
// since we assign the value to n all other bits would have been wiped out if we hadn't kept their original value thanks to the mask on which we do not perform any shift operations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM