views:

1218

answers:

6

Lets say I have a byte with 6 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.

EDIT It would be fine to "toggle" these bits. Even though this is not the same as swapping the bits, toggling works fine for my purposes. Chosen answer below reflects this.

+23  A: 

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);

Skizz

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

Skizz
Don't know why this was downvoted, it's as correct as the others.
Skurmedel
Assuming the OP wants to toggle both bits (as opposed to interchange the two bits), this is the correct answer. OP is using the convention that the LSB is bit 0.
Adam Rosenfield
It's actually slightly more correct, since it's the only answer that operates on the right bits. Still just toggles the state and not *swaps*.
Cirno de Bergerac
Skizz, can you elaborate on *why* x ^= 0x14; toggles both bits? For instance, how could one calculate what hex value toggles bits 1 and 3?
Nate Murray
Matt J
Just for the record, the fact that you wrote the explicit operation as one line doesn't make it "one operation" as the OP requested. that one line of C is made up of 8 separate bit operations, if you count all the shifts, ors and ands there. If you're optimizing for number of operations, you might be better off with the lookup table. On the other hand, one memory access might be much slower than multiple logic operations. At the end of the day, you're best off implementing both and profiling to see which works best in your system.
Nathan Fellman
+10  A: 

Time to answer the question "as written".

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];
Roddy
This is the best if you can spare 256 bytes and if memory accesses are faster than bitwise operations. This varies based on the system. For instance, on modern x86 processors, if the lookup table is in the cache, the lookup is very fast, but if not, you could probably do a few hundred bitwise operations in the time it takes to perform the lookup. In a small embedded controller, you might not have 256 bytes to spare.
Nathan Fellman
+1  A: 

The following method is NOT a single C instruction, its just another bit fiddling method. The method was simplified from the website:

http://graphics.stanford.edu/~seander/bithacks.html#SwappingBitsXOR

As stated above, a look up 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 (i.e. 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 xor'ed 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.

Toddeman
This is a very elegant way to do it. Basically you're saying that if the bits are different (`x` is 1 if they're different) then flip the bits (effectively swapping them), otherwise, leave them unchanged (which is the same as swapping them since they're identical.
Nathan Fellman
+2  A: 

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.

Sinan Ünür
+1  A: 

Simple one, might not be omptimized but 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;
}
santosh pradhan
A: 

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));
aks