12

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.

starblue
  • 55,348
  • 14
  • 97
  • 151
Nate Murray
  • 3,841
  • 5
  • 32
  • 33
  • 3
    Wow three identical answers with different numbers - good luck with that! – Benjol Jun 11 '09 at 15:01
  • 1
    Are you trying to interchange the two bits, or toggle the bits? That is, does 00 become 00 or 11? – Adam Rosenfield Jun 11 '09 at 15:01
  • Can you clarify "swap"? Do you mean bit2 = !bit2, and bit4 = !bit4, or do you mean bit2 = bit4 and bit4 = bit2? – Roddy Jun 11 '09 at 15:02
  • 3
    He said swap, they all did toggle :) – Benjol Jun 11 '09 at 15:02
  • 3
    If the intention here is to swap, as in exchange, the two bit values, then the answers below are all incorrect. – Andre Miller Jun 11 '09 at 15:03
  • 1
    He said swap once and toggle once. :-) – Nosredna Jun 11 '09 at 15:06
  • @Nate Henry, ???0?0?? as an input would lead to what as an output? Can't tell if you want to swap or toggle. – Nosredna Jun 11 '09 at 15:08
  • I think it was confusingly put right from the start. But maybe one got a little caught up in the desire to answer. – Skurmedel Jun 11 '09 at 15:10
  • 1
    Don't forget that even if there is some way to do it in one operation in C it doesn't guarantee that it will be one processor instruction when compiled. – sharptooth Jun 11 '09 at 15:10
  • Doesn't the whole second half of his question imply toggle? I think the work "swap" was just a confusing way to say "toggle." – Nosredna Jun 11 '09 at 15:13
  • I would prefer to swap, but toggling them both would be fine. Lets stick with swap. I'll update the question. – Nate Murray Jun 11 '09 at 15:16
  • 3
    If you're doing it on a known microcontroller you might be better off looking into assembly instructions rather than doing this in C. – Matthew Monaghan Jun 11 '09 at 16:48
  • Sorry to pile on, but we really should get some clarity from Nate as to what the question was (either you need to swap the bit values, or you need to toggle both bits), and change the title and question text appropriately. As it is, there are some good answers here on both fronts, but they will not be easily searchable because the title of the question, text of the question, and answers are all pretty ambiguous as to whether a swap (anew <- bold, bnew <- aold) or toggle (anew <- ~aold, bnew <- ~bold) is required. – Matt J Jun 11 '09 at 19:48
  • If speed is the most important factor, we also need to know which microcontroller you're using, as some have specific bit manipulation instructions, while others don't. If it's an STM32, that has bit-banding, which allows individual bits to be addressed independently, which can be used for very efficient bit twiddling. – Steve Melnikoff Jun 11 '09 at 22:47

8 Answers8

31

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

Skizz
  • 69,698
  • 10
  • 71
  • 108
  • Don't know why this was downvoted, it's as correct as the others. – Skurmedel Jun 11 '09 at 15:02
  • 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 Jun 11 '09 at 15:03
  • 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*. – Nietzche-jou Jun 11 '09 at 15:04
  • 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 Jun 11 '09 at 15:23
  • 1
    @Nate: XORing a bit with 1 will toggle that bit. XORing a bit with 0 will keep it the same. If you want to toggle a certain set of bits in a 32-bit value, create another 32-bit value with the bits you want to toggle set to 1, and the rest 0. In the case of bits 2 and 4, (1 << 2) | (1 << 4) == 0x14. In the case of bits 1 and 3, (1 << 1) && (1 << 3) == 0xA. – Matt J Jun 11 '09 at 18:34
  • 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 Aug 07 '10 at 07:24
11

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
  • 66,617
  • 42
  • 165
  • 277
  • 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 Aug 07 '10 at 07:30
7

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.

Community
  • 1
  • 1
trh178
  • 11,228
  • 5
  • 28
  • 37
  • 2
    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 Aug 07 '10 at 07:34
4

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;
}
Community
  • 1
  • 1
  • 2
    this is incorrect- the (n & mask1) != (n & mask2) will do an integer comparison, but you want to do a boolean comparison. Change to "if (bool(n & mask1) != bool(n & mask2))" will make it correct. – arolson101 Jan 20 '14 at 21:30
  • I think question was about to `swap the two bits not to toggle the bits`. *Was it not?*. – vinod maverick Apr 24 '17 at 03:27
2

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
  • 116,958
  • 15
  • 196
  • 339
1
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.

thiagowfx
  • 4,832
  • 6
  • 37
  • 51
0
#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;
}
Megharaj
  • 1,589
  • 2
  • 20
  • 32
0

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
  • 4,695
  • 8
  • 36
  • 37