Question

Let's say I have a byte with six unknown values:

???1?0??

and I want to swap bits 2 and 4 (without changing any of the ? values):

???0?1??

But how would I do this in one operation in C?

I'm performing this operation thousands of times per second on a microcontroller so performance is the top priority.

It would be fine to "toggle" these bits. Even though this is not the same as swapping the bits, toggling would work fine for my purposes.

Was it helpful?

Solution

Try:

x ^= 0x14;

That toggles both bits. It's a little bit unclear in question as you first mention swap and then give a toggle example. Anyway, to swap the bits:

x = precomputed_lookup [x];

where precomputed_lookup is a 256 byte array, could be the fastest way, it depends on the memory speed relative to the processor speed. Otherwise, it's:

x = (x & ~0x14) | ((x & 0x10) >> 2) | ((x & 0x04) << 2);

EDIT: Some more information about toggling bits.

When you xor (^) two integer values together, the xor is performed at the bit level, like this:

for each (bit in value 1 and value 2)
   result bit = value 1 bit xor value 2 bit

so that bit 0 of the first value is xor'ed with bit 0 of the second value, bit 1 with bit 1 and so on. The xor operation doesn't affect the other bits in the value. In effect, it's a parallel bit xor on many bits.

Looking at the truth table for xor, you will see that xor'ing a bit with the value '1' effectively toggles the bit.

 a  b a^b
 0  0  0
 0  1  1
 1  0  1
 1  1  0

So, to toggle bits 1 and 3, write a binary number with a one where you want the bit to toggle and a zero where you want to leave the value unchanged:

00001010

convert to hex: 0x0a. You can toggle as many bits as you want:

0x39 = 00111001

will toggle bits 0, 3, 4 and 5

OTHER TIPS

You cannot "swap" two bits (i.e. the bits change places, not value) in a single instruction using bit-fiddling.

The optimum approach if you want to really swap them is probably a lookup table. This holds true for many 'awkward' transformations.

BYTE lookup[256] = {/* left this to your imagination */};

for (/*all my data values */) 
  newValue = lookup[oldValue];

The following method is NOT a single C instruction, it's just another bit fiddling method. The method was simplified from Swapping individual bits with XOR.

As stated in Roddy's answer, a lookup table would be best. I only suggest this in case you didn't want to use one. This will indeed swap bits also, not just toggle (that is, whatever is in bit 2 will be in 4 and vice versa).

  • b: your original value - ???1?0?? for instance
  • x: just a temp
  • r: the result

    x = ((b >> 2) ^ (b >> 4)) & 0x01
    r = b ^ ((x << 2) | (x << 4))

Quick explanation: get the two bits you want to look at and XOR them, store the value to x. By shifting this value back to bits 2 and 4 (and OR'ing together) you get a mask that when XORed back with b will swap your two original bits. The table below shows all possible cases.

bit2: 0 1 0 1  
bit4: 0 0 1 1  
x   : 0 1 1 0   <-- Low bit of x only in this case 
r2  : 0 0 1 1  
r4  : 0 1 0 1

I did not fully test this, but for the few cases I tried quickly it seemed to work.

This might not be optimized, but it should work:

unsigned char bit_swap(unsigned char n, unsigned char pos1, unsigned char pos2)
{
    unsigned char mask1 = 0x01 << pos1;
    unsigned char mask2 = 0x01 << pos2;
   if ( !((n & mask1) != (n & mask2)) )
        n ^= (mask1 | mask2);
    return n;
}

The function below will swap bits 2 and 4. You can use this to precompute a lookup table, if necessary (so that swapping becomes a single operation):

unsigned char swap24(unsigned char bytein) {
    unsigned char mask2 = ( bytein & 0x04 ) << 2;
    unsigned char mask4 = ( bytein & 0x10 ) >> 2;
    unsigned char mask  = mask2 | mask4 ;
    return ( bytein & 0xeb ) | mask;
}

I wrote each operation on a separate line to make it clearer.

Say your value is x i.e, x=???1?0??

The two bits can be toggled by this operation:

x = x ^ ((1<<2) | (1<<4));
#include<stdio.h>

void printb(char x) {
    int i;
    for(i =7;i>=0;i--) 
        printf("%d",(1 & (x >> i)));
    printf("\n");
}

int swapb(char c, int p, int q) {
    if( !((c & (1 << p)) >> p) ^ ((c & (1 << q)) >> q) )
        printf("bits are not same will not be swaped\n");
    else {
        c = c ^ (1 << p);
        c = c ^ (1 << q);
    }
    return c;
}

int main() 
{
    char c = 10;
    printb(c);
    c = swapb(c, 3, 1);
    printb(c);
    return 0;
}
void swap_bits(uint32_t& n, int a, int b) {
    bool r = (n & (1 << a)) != 0;
    bool s = (n & (1 << b)) != 0;

    if(r != s) {
        if(r) {
            n |= (1 << b);
            n &= ~(1 << a);
        }
        else {
            n &= ~(1 << b);
            n |= (1 << a);
        }
    }
}

n is the integer you want to be swapped in, a and b are the positions (indexes) of the bits you want to be swapped, counting from the less significant bit and starting from zero.

Using your example (n = ???1?0??), you'd call the function as follows:

swap_bits(n, 2, 4);

Rationale: you only need to swap the bits if they are different (that's why r != s). In this case, one of them is 1 and the other is 0. After that, just notice you want to do exactly one bit set operation and one bit clear operation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top