Is it safe to use -1 to set all bits to true?

Viewed 41402

I've seen this pattern used a lot in C & C++.

unsigned int flags = -1;  // all bits are true

Is this a good portable way to accomplish this? Or is using 0xffffffff or ~0 better?

21 Answers

I recommend you to do it exactly as you have shown, since it is the most straight forward one. Initialize to -1 which will work always, independent of the actual sign representation, while ~ will sometimes have surprising behavior because you will have to have the right operand type. Only then you will get the most high value of an unsigned type.

For an example of a possible surprise, consider this one:

unsigned long a = ~0u;

It won't necessarily store a pattern with all bits 1 into a. But it will first create a pattern with all bits 1 in an unsigned int, and then assign it to a. What happens when unsigned long has more bits is that not all of those are 1.

And consider this one, which will fail on a non-two's complement representation:

unsigned int a = ~0; // Should have done ~0u !

The reason for that is that ~0 has to invert all bits. Inverting that will yield -1 on a two's complement machine (which is the value we need!), but will not yield -1 on another representation. On a one's complement machine, it yields zero. Thus, on a one's complement machine, the above will initialize a to zero.

The thing you should understand is that it's all about values - not bits. The variable is initialized with a value. If in the initializer you modify the bits of the variable used for initialization, the value will be generated according to those bits. The value you need, to initialize a to the highest possible value, is -1 or UINT_MAX. The second will depend on the type of a - you will need to use ULONG_MAX for an unsigned long. However, the first will not depend on its type, and it's a nice way of getting the most highest value.

We are not talking about whether -1 has all bits one (it doesn't always have). And we're not talking about whether ~0 has all bits one (it has, of course).

But what we are talking about is what the result of the initialized flags variable is. And for it, only -1 will work with every type and machine.

  • unsigned int flags = -1; is portable.
  • unsigned int flags = ~0; isn't portable because it relies on a two's-complement representation.
  • unsigned int flags = 0xffffffff; isn't portable because it assumes 32-bit ints.

If you want to set all bits in a way guaranteed by the C standard, use the first one.

Frankly I think all fff's is more readable. As to the comment that its an antipattern, if you really care that all the bits are set/cleared, I would argue that you are probably in a situation where you care about the size of the variable anyway, which would call for something like boost::uint16_t, etc.

A way which avoids the problems mentioned is to simply do:

unsigned int flags = 0;
flags = ~flags;

Portable and to the point.

I am not sure using an unsigned int for flags is a good idea in the first place in C++. What about bitset and the like?

std::numeric_limit<unsigned int>::max() is better because 0xffffffff assumes that unsigned int is a 32-bit integer.

As long as you have #include <limits.h> as one of your includes, you should just use

unsigned int flags = UINT_MAX;

If you want a long's worth of bits, you could use

unsigned long flags = ULONG_MAX;

These values are guaranteed to have all the value bits of the result set to 1, regardless of how signed integers are implemented.

I would not do the -1 thing. It's rather non-intuitive (to me at least). Assigning signed data to an unsigned variable just seems to be a violation of the natural order of things.

In your situation, I always use 0xFFFF. (Use the right number of Fs for the variable size of course.)

[BTW, I very rarely see the -1 trick done in real-world code.]

Additionally, if you really care about the individual bits in a vairable, it would be good idea to start using the fixed-width uint8_t, uint16_t, uint32_t types.

On Intel's IA-32 processors it is OK to write 0xFFFFFFFF to a 64-bit register and get the expected results. This is because IA32e (the 64-bit extension to IA32) only supports 32-bit immediates. In 64-bit instructions 32-bit immediates are sign-extended to 64-bits.

The following is illegal:

mov rax, 0ffffffffffffffffh

The following puts 64 1s in RAX:

mov rax, 0ffffffffh

Just for completeness, the following puts 32 1s in the lower part of RAX (aka EAX):

mov eax, 0ffffffffh

And in fact I've had programs fail when I wanted to write 0xffffffff to a 64-bit variable and I got a 0xffffffffffffffff instead. In C this would be:

uint64_t x;
x = UINT64_C(0xffffffff)
printf("x is %"PRIx64"\n", x);

the result is:

x is 0xffffffffffffffff

I thought to post this as a comment to all the answers that said that 0xFFFFFFFF assumes 32 bits, but so many people answered it I figured I'd add it as a separate answer.

See litb's answer for a very clear explanation of the issues.

My disagreement is that, very strictly speaking, there are no guarantees for either case. I don't know of any architecture that does not represent an unsigned value of 'one less than two to the power of the number of bits' as all bits set, but here is what the Standard actually says (3.9.1/7 plus note 44):

The representations of integral types shall define values by use of a pure binary numeration system. [Note 44:]A positional representation for integers that uses the binary digits 0 and 1, in which the values represented by successive bits are additive, begin with 1, and are multiplied by successive integral power of 2, except perhaps for the bit with the highest position.

That leaves the possibility for one of the bits to be anything at all.

It is certainly safe, as -1 will always have all available bits set, but I like ~0 better. -1 just doesn't make much sense for an unsigned int. 0xFF... is not good because it depends on the width of the type.

Practically: Yes

Theoretically: No.

-1 = 0xFFFFFFFF (or whatever size an int is on your platform) is only true with two's complement arithmetic. In practice, it will work, but there are legacy machines out there (IBM mainframes, etc.) where you've got an actual sign bit rather than a two's complement representation. Your proposed ~0 solution should work everywhere.

Leveraging on the fact that assigning all bits to one for an unsigned type is equivalent to taking the maximum possible value for the given type,
and extending the scope of the question to all unsigned integer types:

Assigning -1 works for any unsigned integer type (unsigned int, uint8_t, uint16_t, etc.) for both C and C++.

As an alternative, for C++, you can either:

  1. Include <limits> and use std::numeric_limits< your_type >::max()
  2. Write a custom templated function (This would also allow some sanity check, i.e. if the destination type is really an unsigned type)

The purpose could be add more clarity, as assigning -1 would always need some explanatory comment.

A way to make the meaning bit more obvious and yet to avoid repeating the type:

const auto flags = static_cast<unsigned int>(-1);

An additional effort to emphasize, why Adrian McCarthy's approach here might be the best solution at latest since C++11 in terms of a compromise between standard conformity, type safety/explicit clearness and reduction of possible ambiguities:

unsigned int flagsPreCpp11 = ~static_cast<unsigned int>(0);
auto flags = ~static_cast<unsigned int>(0); // C++11 initialization
predeclaredflags = ~static_cast<decltype(predeclaredflags)>(0); // C++11 assignment to already declared variable

I'm going to explain my preference in detail below. As Johannes mentioned totally correctly, the fundamental origin of irritations here is the question about value vs. according bit representation semantics and about what types we're talking about exactly (the assigned value type vs. the possible compile time integral constant's type). Since there's no standard built-in mechanism to explicitly ensure the set of all bits to 1 for the concrete use case of the OP about unsigned integer values, it's obvious, that it's impossible to be fully independent of value semantics here (std::bitset is a common pure bit-layer refering container but the question was about unsigned integers in general). But we might be able to reduce ambiguity here.

Comparison of the 'better' standard compliant approaches:

The OP's way:

unsigned int flags = -1;

PROs:

  • is "established" and short
  • is quite intuitive in terms of modulo perspective of value to "natural" bit value representation
  • changing the target unsigned type to unsigned long for instance is possible without any further adaptions

CONs:

  • At least beginners might not be sure about the standard conformity ("Do I have to concern about padding bits?").
  • Violates type ranges (in the heavier way: signed vs. unsigned).
  • Solely from the code, you do not directly see any bit semantics association.

Refering to maximum values via defines:

unsigned int flags = UINT_MAX;

This circumvents the signed unsigned transition issue of the -1 approach but introduces several new problems: In doubt, one has to look twice here again, at the latest if you want to change the target type to unsigned long for instance. And here, one has to be sure about the fact, that the maximum value leads to all bits set to 1 by the standard (and padding bit concerns again). Bit semantics are also not obvious here directly from the code solely again.

Refering to maximum values more explicitly:

auto flags = std::numeric_limits<unsigned int>::max();

On my opinion, that's the better maximum value approach since it's macro/define free and one is explicit about the involved type. But all other concerns about the approach type itself remain.

Adrian's approach (and why I think, it's the preferred one before C++11 and since):

unsigned int flagsPreCpp11 = ~static_cast<unsigned int>(0);
auto flagsCpp11 = ~static_cast<unsigned int>(0);

PROs:

  • Only the simplest integral compile time constant is used: 0. So no worries about further bit representation or (implicit) casts are justified. From an intuitive point of view, I think we all can agree on the fact, that the bit representation for zero is commonly clearer than for maximum values, not only for unsigned integrals.
  • No type ambiguities are involved, no further look-ups required in doubt.
  • Explicit bit semantics are involved here via the complement ~. So it's quite clear from the code, what the intention was. And it's also very explicit, on which type and type range, the complement is applied.

CONs:

If assigned to a member for instance, there's a small chance that you mismatch types with pre C++11:

Declaration in class:

unsigned long m_flags;

Initialization in constructor:

m_flags(~static_cast<unsigned int>(0))

But since C++11, the usage of decltype + auto is powerful to prevent most of these possible issues. And some of these type mismatch scenarios (on interface boundaries for instance) are also possible for the -1 approach.

Robust final C++11 approach for pre-declared variables:

m_flags(~static_cast<decltype(m_flags)>(0)) // member initialization case

So with a full view on the weighting of the PROs and CONs of all approaches here, I recommend this one as the preferred approach, at latest since C++11.

Update: Thanks to a hint by Andrew Henle, I removed the statement about its readability since that might be a too subjective statement. But I still think, its readability is at least not that worse than most of the maximum value approaches or the ones with explicit maximum value provision via compile time integrals/literals since static_cast-usage is "established" too and built-in in contrast to defines/macros and even the std-lib.

Related