5

If I want to flip some bits, I was wondering which way is better. Should I flip them using XOR 0xffffffff or by using ~?

I'm afraid that there will be some cases where I might need to pad bits onto the end in one of these ways and not the other, which would make the other way safer to use. I'm wondering if there are times when it's better to use one over the other.

Here is some code that uses both on the same input value, and the output values are always the same.

#include <iostream>
#include <iomanip>

void flipBits(unsigned long value)
{
    const unsigned long ORIGINAL_VALUE = value;
    std::cout << "Original value:" << std::setw(19) << std::hex << value << std::endl;

    value ^= 0xffffffff;
    std::cout << "Value after XOR:" << std::setw(18) << std::hex << value << std::endl;

    value = ORIGINAL_VALUE;
    value = ~value;
    std::cout << "Value after bit negation: " << std::setw(8) << std::hex << value << std::endl << std::endl;
}

int main()
{
    flipBits(0x12345678);
    flipBits(0x11223344);
    flipBits(0xabcdef12);
    flipBits(15);
    flipBits(0xffffffff);
    flipBits(0x0);
    return 0;
}

Output:

Original value:           12345678
Value after XOR:          edcba987
Value after bit negation: edcba987

Original value:           11223344
Value after XOR:          eeddccbb
Value after bit negation: eeddccbb

Original value:           abcdef12
Value after XOR:          543210ed
Value after bit negation: 543210ed

Original value:                  f
Value after XOR:          fffffff0
Value after bit negation: fffffff0

Original value:           ffffffff
Value after XOR:                 0
Value after bit negation:        0

Original value:                  0
Value after XOR:          ffffffff
Value after bit negation: ffffffff
Programmer_D
  • 601
  • 2
  • 15
  • 27
  • Define what would make one "better"? – FatalError Sep 26 '14 at 17:48
  • `~` will always flip everything, regardless of the size of the type. It's also less typing. – Oliver Charlesworth Sep 26 '14 at 17:48
  • 2
    I think that 'smart' ideas like this one are the ones making our codebases a nightmare – gd1 Sep 26 '14 at 17:52
  • Is there a way I could improve this question? I'm not sure what the downvote is for. – Programmer_D Sep 26 '14 at 17:58
  • I [answered a similar question](http://stackoverflow.com/questions/22367511/bitwise-operators-not-vs-xor-use-in-branching/22386426#22386426) in the past, about the only benefit you _might_ see is about 1-byte smaller byte-code if the compiler interprets your expression literally on x86 since it can XOR and set the CF flag in 1-byte fewer than the equivalent NOT and TEST instructions. Otherwise, you just make your code more confusing than it needs to be. – Andon M. Coleman Sep 26 '14 at 17:59
  • PLEASE: don't mix signed/unsigned integers like `const int ORIGINAL_VALUE = value;` – TemplateRex Sep 26 '14 at 18:01
  • @AndonM.Coleman That's good to know. I was actually wondering if I sometimes, for example, I would end up not flipping all the bits using `XOR` – Programmer_D Sep 26 '14 at 18:01
  • 1
    Sure, if the platform's not 32-bit. You should negate 0U instead of a constant like 0xffffffff. – Andon M. Coleman Sep 26 '14 at 18:03
  • @TemplateRex Thanks, I wasn't paying too close attention when I wrote out this example. I edited it. – Programmer_D Sep 26 '14 at 18:04

2 Answers2

13

Use ~:

  • You won't be relying on any specific width of the type; for example, int is not 32 bits on all platforms.
  • It removes the risk of accidentally typing one f too few or too many.
  • It makes the intent clearer.
Thomas
  • 174,939
  • 50
  • 355
  • 478
  • +1 although the extra `f` problem is solved by C++14 digit separators, e.g. in groups of 4 like `0xffff'ffff` – TemplateRex Sep 26 '14 at 18:10
  • 2
    Isn't it actually `~` that runs the risk of flipping too many bits? You never know how many it's going to be this time. – harold Sep 26 '14 at 18:20
  • 1
    @harold That's another thing I was worried about, actually. I saw in [this StackOverflow question](http://stackoverflow.com/questions/12084364/c-bitwise-negation-creates-negative-output) that it might even be possible to get negative numbers sometimes. – Programmer_D Sep 26 '14 at 18:25
  • @harold That's why I would rather recommend `std::bitset` in this case, because the number of bit operated on is specifically defined. – πάντα ῥεῖ Sep 26 '14 at 18:26
  • @Programmer_D well yea on a signed number.. signed numbers cause no end of "funny stuff", that question actually shows one of the more reasonable parts. – harold Sep 26 '14 at 18:28
  • @Programmer_D _"That's another thing I was worried about, actually ..."_ That should be healed by using the idiom described in my answer. `std::bitset` handles a **fixed number** of bits at hand of your choice. – πάντα ῥεῖ Sep 26 '14 at 18:36
  • @πάνταῥεῖ Vielen Dank (thank you), I gave you a +1 =) I wrote the C++ part in the question because that is what I was using, but I kind of meant it to be more general. And good point, Harold! I should have noticed that one was using signed values. – Programmer_D Sep 26 '14 at 19:34
5

As you're asking for specifically, simply use std::bitset

#include <iostream>
#include <iomanip>
#include <bitset>
#include <limits>

void flipBits(unsigned long value) {
    std::bitset<std::numeric_limits<unsigned long>::digits> bits(value);
    std::cout << "Original value : 0x" << std::hex << value;

    value = bits.flip().to_ulong();
    std::cout << ", Value after flip: 0x" << std::hex << value << std::endl;
}

See live demo.

As for your mentioned concerns, of just using the ~ operator with the unsigned long value, and having more bits flipped as actually wanted:
Since std::bitset<NumberOfBits> actually specifies the number of bits, that should be operated on, it will well solve such problems correctly.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190