147

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?

Antonio
  • 19,451
  • 13
  • 99
  • 197
hyperlogic
  • 7,525
  • 7
  • 39
  • 32
  • 8
    I think whether the meaning of the code is clear is the most important question. Even though `-1` will always work, the fact that a comment is needed after it shows that it's not clear code. If the variable is meant to be a collection of flags, why assign it an integer? Its type may be an integer, but its certainly not semantically an integer. You're never going to increment it or multiply it. So I would use `0xffffffff` not for portability or correctness, but for clarity. – Cam Jackson Jun 04 '12 at 06:31
  • @CamJackson the comment *isn't* and anyone writing C code could be familiar with how values are represented. – Miles Rout Aug 25 '18 at 11:00
  • The question originally was properly tagged as C and C++. The languages may be diverging in that C++ has a proposal to require two's complement. That said, it doesn't change the fact that `-1` remains a portable and backward compatible solution for both languages, but it could affect some of the reasoning in other answers. – Adrian McCarthy May 03 '19 at 17:31

21 Answers21

169

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 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.

wovano
  • 4,543
  • 5
  • 22
  • 49
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 10
    why is -1 guaranteed to be converted to all ones? Is that guaranteed by the standard? – jalf Apr 30 '09 at 22:11
  • 9
    the conversion that happens is that it repeatedly adds one more than ULONG_MAX until it is in range (6.3.1.3 in the C TC2 draft). In C++ it's the same, just using another way formalizing it (modulo 2^n). It all comes down to mathematical relations. – Johannes Schaub - litb Apr 30 '09 at 22:18
  • 1
    instead of `-1`, you could also use `UINTMAX_MAX` from stdint.h as a type-agnostic initialisation value; but one would assume that the programmer knows the number of significant bits of the flags variable, so there's nothing wrong with `0xff...` either – Christoph May 03 '09 at 20:12
  • Sometimes, it's convenient to use the highest value for something special. Like std::string::npos, which is defined as static_cast(-1) . The number of bits is not necessarily needed in such cases. – Johannes Schaub - litb May 03 '09 at 20:52
  • 6
    @litb: casting -1 is certainly a nice way to get maximal unsigned values, but it's not really descriptive; that's the reason why the _MAX constants exist (SIZE_MAX was added in C99); granted, the C++ version `numeric_limits::max()` is a bit long-winded, but so is the cast... – Christoph May 03 '09 at 22:07
  • I think this answer's right in practice, but I can't see an absolute guarantee in the Standard that 2^N - 1 is all bits set for an unsigned type. I'm adding an answer to that effect. – James Hopkin May 12 '09 at 13:32
  • 3
    Beware of ones' complement representation (seen in a few obscure DSP chips.) – finnw Jun 08 '09 at 15:13
  • 13
    "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)." -- whaat??? I thought the whole point *was* to set all bits to 1. That's how flags work..no?? You look at the *bits*. Who cares about the value? – mpen Aug 01 '10 at 21:11
  • 16
    @Mark the questioner cares. He asks "Is it safe to use -1 to set all bits to true". This does not ask about what bits `-1` is represented by, nor does it ask what bits `~0` has. We may not care about values, but the compiler does. We can't ignore the fact that operations work with and by values. The *value* of `~0` may not be `-1`, but this is the value you need. See my answer and @Dingo's summary. – Johannes Schaub - litb Aug 02 '10 at 04:20
  • @Johannes: Well.. why is the "highest value" guaranteed to have "all bit set" then? – mpen Aug 04 '10 at 01:57
  • @Mark because the standard integers are using a pure binary system for counting. If you always count up.. you end at all bits 1 some day :) You can argue an implementation could define the highest unsigned number unequal to `2**n - 1`, but then such an impl would have a problem with implementing the conversion of `-1` to `unsigned`, which precisely is required to result in a value of `2**n - 1` with `n` being the amount of bits in the unsigned type. – Johannes Schaub - litb Aug 04 '10 at 19:00
  • 4
    @Adrian can you provide a quote of me doing so? No, you can always do `unsigned int flags = static_cast(-1);` if your compiler is too picky. Nothing needs to be disabled. – Johannes Schaub - litb Jun 22 '11 at 12:07
  • 1
    @JohannesSchaub-litb: You said to do it _exactly_ as posed in the question, which does not have the cast and thus requires disabling a compiler warning. – Adrian McCarthy Jun 10 '12 at 16:59
  • 3
    @AdrianMcCarthy casts should be avoided where possible but to disable compiler warnings isn't necessarily a good thing either. The latter depends on how fine you can control the warning of your compiler. The cast introduces said dependency in your code (`unsigned long x = (unsigned int)-1;` - oops!). So regarding the code itself, omitting the cast definitely is the best you can do. I don't feel experienced enough with the various compilers out there to put out a statement wrt their warnings and flags. – Johannes Schaub - litb Jun 10 '12 at 17:07
  • 1
    @JohannesSchaub-litb: With C++11, you can use `auto` to avoid the potential for incorrect casting by avoiding the duplication of the type (see my answer). The result is correct, portable, warning-free, and obvious to other programmers. The confusion demonstrated throughout this question shows that the -1 trick is not obvious to many programmers and thus a dangerous idiom to use in your code. – Adrian McCarthy Dec 11 '12 at 18:36
  • 2
    I still don't quite get why you are recommending the use of -1 because on one's complement machines -1 is `11111110` (not all 1s). Only in 2's complement is it all 1s. So why are you recommending it? – David G Mar 15 '13 at 01:42
  • 7
    @0x499602D2 As litb already explained, signed->unsigned conversion does not involve _bit representations_, it involves _numeric values_ (with "modulo N" arithmetic). After `unsigned int a = -1;` the value of `a` is equal to "-1 modulo UINT_MAX+1" (positive remainder), which is here `(UINT_MAX + 1) - 1` i.e. `UINT_MAX`, whose bit representation is all 1s (even on one's complement machines). – gx_ Jun 22 '13 at 16:37
  • @JohannesSchaub-litb C99 in section 6.3.1.3, "signed and unsigned integers" says that *if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type*. I understand that `-1` works if addition is used, but what if if subtracts? I mean, `-1 - (UXX_MAX+1)` will never be in the range of an unsigned type. Is this an inconsistency in the standard? Do you know if C++ has the same rule? – Filipe Gonçalves Mar 04 '14 at 11:11
  • @FilipeGonçalves well there's the other case where the initial value is too high, then it will subtract. So `UXX_MAX+2` will end up as `1`. – Johannes Schaub - litb Mar 05 '14 at 09:28
57
  • 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.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Dingo
  • 3,305
  • 18
  • 14
  • 11
    How does ~0 (i.e. the one's complement operator) rely on two's complement representation? – Drew Hall May 01 '09 at 04:18
  • 11
    You have this backwards. Its setting flags to -1 that relies on a twos complement representation. In a sign+magnitude representation minus one only has two bits set: the sign bit and the least significant bit of the magnitude. – Stephen C. Steel May 01 '09 at 04:50
  • 15
    The C standard requires that int value of zero has its sign bit and all value bits are zero. After the one's complement, all those bits are one. The values of an int with all bits set are: Sign-and-magnitude: INT_MIN One's complement: -0 Two's complement: -1 So the statement "unsigned int flags = ~0;" will assign whichever value above matches the platform's integer representation. But the '-1' of two's complement is the only one that will set all the flags bits to one. – Dingo May 01 '09 at 04:56
  • 11
    @Stephen: Agreed on the representation. But when an int value is assigned to an unsigned int, the unsigned doesn't get its value by adopting the int value's internal representation (except in two's-complement systems where that generally works). All values assigned to unsigned int's are modulo (UINT_MAX + 1), so assigning -1 works no matter the internal representation. – Dingo May 01 '09 at 05:14
  • 1
    @Stephen: dingoatemydonut's right -- surprisingly enough, C++ guarantees this, it's in section 4.7, paragraph 2 of the ISO standard. – j_random_hacker May 01 '09 at 06:12
  • @Dingo: What's so important about the distinction between "all bits" and "flag bits". If I go `flags=~0` and then I want to check if the first bit is set, `flags&1`, will that not work in all cases? – mpen Aug 01 '10 at 21:17
  • 4
    @Mark There is no intended distinction between "all bits" and "all the flag bits". They are the same. The expression "flags = ~0" will not always work if flags is unsigned. The simplest example is on a one's-complement platform. On such a platform "~x == -x" is true for signed integers. Therefore, "~0 == -0" is true. On that platform, "flags = ~0" is the same as "flags = -0", which in turn is the same as "flags = 0". So on a one's-complement platform "flags = ~0" results in no bits being set. – Dingo Aug 03 '10 at 21:23
  • @Dingo: Oh...that clarifies it.. but also makes no sense at all. Not quite sure how "~0 == 0 == no bits set".. that just sounds like an error. The ~ is supposed to invert the bits.. it seems like it's failing to do so?? – mpen Aug 04 '10 at 01:49
  • 27
    @Mark: you're confusing two operations. `~0` yields an `int` value with all bits set, of course. But assigning an `int` to an `unsigned int` does not *necessarily* result in the unsigned int having the same bit pattern as the signed bit pattern. Only with a 2's complement representation is this always the case. On a 1s' complement or sign-magnitude representation, assigning a negative `int` value to an `unsigned int` results in a different bit pattern. This is because the C++ standard defines signed -> unsigned conversion to be the modulo-equal value, not the value with the same bits. – Steve Jessop Aug 06 '10 at 00:46
  • 2
    I still have confusion on why `-1` is the portable way. consider `-1` on an 1's complement system, having `4 bit` width of integer. So, `1 = 0001b`, `-1 = 1110b`. `unsigned int flags = -1` should assign `1110b` to flags, isn't it? – Donotalo May 11 '11 at 08:37
  • 2
    @Donotalo: On a one's-complement system, typecasting a negative signed int to an unsigned int does not simply reinterpret the same bit pattern, but instead generates whatever bit pattern would correspond to (integer value + UNSIGNED_MAX). – supercat May 31 '11 at 20:48
  • @supercat: so for `unsigned int flags = -1` the variable `flags` will contain `1110b + 1111b = 0001b`? what am i missing? – Donotalo Jun 01 '11 at 04:10
  • 3
    @Donotalo: What you are missing is that the rules for casting a signed type to an unsigned type require that *regardless of the bit representation* -1 will turn into the value which, when added to +1, will yield zero, i.e. the maximum value for the unsigned type. Note that if has a signed variable holding -1 and one accesses the memory uses a (unsigned char*), there's no guarantee that all the unsigned char's comprising the variable will have all their bits set. The guarantee that (unsigned whatever)(-1) has all the bits set only applies with explicit casts, not with memory overlays. – supercat Jun 01 '11 at 14:16
  • 1
    `unsigned int flags = ~0` isn't portable but `unsigned int flags = ~0U` is portable, and expresses the intent clearer – phuclv Aug 07 '18 at 11:15
24

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.

Doug T.
  • 64,223
  • 27
  • 138
  • 202
  • There are a number of cases in which you don't care that much, but they're rare. E.g. algorithms that work on datasets of N bits by breaking it down into chunks of sizeof(unsigned)*CHAR_BIT bits each. – MSalters May 04 '09 at 07:22
  • 2
    +1. Even if the size of the datatype is bigger than the # of F's (i.e., you didn't quite set all the bits to true), since you're explicitly setting the value, you are at least aware of which bits are "safe to use".. – mpen Aug 01 '10 at 21:20
17

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

unsigned int flags = 0;
flags = ~flags;

Portable and to the point.

hammar
  • 138,522
  • 17
  • 304
  • 385
  • 4
    But then you lose the ability to declare `flags` as `const`. – David Stone Aug 28 '12 at 04:46
  • 1
    @DavidStone `unsigned int const flags = ~0u;` –  Dec 12 '12 at 00:36
  • @Zoidberg'-- That fails to work on systems other than two's complement. For instance, on a sign-magnitude system, `~0` is an integer that has all bits set to 1, but when you then assign that `int` to the `unsigned` variable `flags`, you perform a value conversion from `-2**31` (assuming a 32-bit `int`) to `(-2**31 % 2**32) == 2**31`, which is an integer with all bits but the first set to 1. – David Stone Dec 12 '12 at 01:53
  • That is also a reason why this answer is dangerous. It seems as though @Zoidberg'--'s answer would be identical, but it actually isn't. However, as a person reading the code, I would have to think about it to understand why you took two steps to initialize it, and possibly be tempted to change that to a single step. – David Stone Dec 12 '12 at 02:28
  • @DavidStone `~0u` is an `unsigned int`, not an `int`. –  Dec 12 '12 at 11:21
  • 2
    Ah yes, I didn't notice the `u` suffix in your answer. That would of course work, but still has the problem of specifying the data type you use (`unsigned` and no larger) twice, which could lead to errors. The error is most likely to show up if the assignment and initial variable declaration are farther apart, though. – David Stone Dec 13 '12 at 01:26
14
unsigned int flags = -1;  // all bits are true

"Is this a good[,] portable way to accomplish this?"

Portable? Yes.

Good? Debatable, as evidenced by all the confusion shown on this thread. Being clear enough that your fellow programmers can understand the code without confusion should be one of the dimensions we measure for good code.

Also, this method is prone to compiler warnings. To elide the warning without crippling your compiler, you'd need an explicit cast. For example,

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

The explicit cast requires that you pay attention to the target type. If you're paying attention to the target type, then you'll naturally avoid the pitfalls of the other approaches.

My advice would be to pay attention to the target type and make sure there are no implicit conversions. For example:

unsigned int flags1 = UINT_MAX;
unsigned int flags2 = ~static_cast<unsigned int>(0);
unsigned long flags3 = ULONG_MAX;
unsigned long flags4 = ~static_cast<unsigned long>(0);

All of which are correct and more obvious to your fellow programmers.

And with C++11: We can use auto to make any of these even simpler:

auto flags1 = UINT_MAX;
auto flags2 = ~static_cast<unsigned int>(0);
auto flags3 = ULONG_MAX;
auto flags4 = ~static_cast<unsigned long>(0);

I consider correct and obvious better than simply correct.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175
  • +1 for providing the best portable, more explicit and better readable alternative IMO: ~static_cast(0) – Secundi Feb 04 '21 at 10:43
14

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.

Akhil Jain
  • 13,872
  • 15
  • 57
  • 93
Edouard A.
  • 6,100
  • 26
  • 31
  • I like this because of its standard, but it's too wordy and it makes you state the type twice. Using ~0 is probably safer since 0 can be any integer type. (Although I'm aware it smells too much of C.) – Macke Apr 30 '09 at 21:46
  • The fact it is wordy can be seen as an advantage. But I like ~0 as well. – Edouard A. Apr 30 '09 at 21:49
  • 2
    You can mitigate the wordiness with the standard UINT_MAX macro, since you're hardcoding the type unsigned int anyway. –  Jan 10 '10 at 21:40
  • 2
    @Macke You can avoid stating the type in C++11 with `auto`. `auto const flags = std::numeric_limit::max()`. – David Stone Dec 12 '12 at 01:55
12

Converting -1 into any unsigned type is guaranteed by the standard to result in all-ones. Use of ~0U is generally bad since 0 has type unsigned int and will not fill all the bits of a larger unsigned type, unless you explicitly write something like ~0ULL. On sane systems, ~0 should be identical to -1, but since the standard allows ones-complement and sign/magnitude representations, strictly speaking it's not portable.

Of course it's always okay to write out 0xffffffff if you know you need exactly 32 bits, but -1 has the advantage that it will work in any context even when you do not know the size of the type, such as macros that work on multiple types, or if the size of the type varies by implementation. If you do know the type, another safe way to get all-ones is the limit macros UINT_MAX, ULONG_MAX, ULLONG_MAX, etc.

Personally I always use -1. It always works and you don't have to think about it.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • FWIW, if I mean “all 1 bits” I use `~(type)0` (well, fill in the right `type` of course). Casting zero still results in a zero, so that's clear, and negating all the bits in the target type is pretty clearly defined. It's not that often that I actually want that operation though; YMMV. – Donal Fellows Aug 01 '10 at 21:12
  • @Donal, that surely works, but requires knowing the type and writing it out directly. Perhaps this would be better: `var=~(0*var);` since it won't break if the type changes. I still prefer -1. – R.. GitHub STOP HELPING ICE Aug 03 '10 at 11:05
  • -1 has the assumption that you're working with twos-complement arithmetic. Almost everything does nowadays, but not all. – Donal Fellows Aug 04 '10 at 08:45
  • 9
    @Donal: you are simply wrong. C specifies that, when converting a value that does not fit into an unsigned type, the values is reduced modulo 2^n where n is the number of bits in destination type. This applies both to signed values and larger unsigned types. It has nothing to do with twos complement. – R.. GitHub STOP HELPING ICE Aug 04 '10 at 10:48
  • @R..: You've described what happens with twos-complement architectures (the overwhelmingly most common) but there's also ones-complement and sign-value, and to expect that those implement sign/bit conversions the same is just unrealistic, no matter what the standard says. After all, it's “just a standard” and compliance is not usually valued as much as supporting old code. – Donal Fellows Aug 04 '10 at 22:04
  • And as noted, I use the form from earlier in this exchange. That's not because it is shorter, but because it says “this is working with bits” to me whereas `-1` says “this is working with the value”. – Donal Fellows Aug 04 '10 at 22:06
  • 2
    They **do** implement it the same, which is trivial; you just use an unsigned subtraction opcode instead of a signed one or a `neg` instruction. Machines which have bogus signed arithmetic behavior have separate signed/unsigned arithmetic opcodes. Of course a really good compiler would just always ignore the signed opcodes even for signed values and thereby get twos-complement for free. – R.. GitHub STOP HELPING ICE Aug 05 '10 at 04:41
  • 1
    @R.: The `var = ~(0*var)` case will fail for `var` being an unsigned type narrower than `int`. Perhaps `var = ~(0U*var)` ? (personally I still prefer `-1`, though). – caf Dec 23 '10 at 00:58
  • 1
    This answer is much clearer than Johannes Schaub's. However, assigning a negative literal integer to an unsigned type without a cast typically results in a compiler warning. Suppressing the warning requires a cast, which means to have to pay attention to the target type anyway, so you may as well use UINT_MAX or ULONG_MAX and be clear rather than relying on a tiny detail in the standard the clearly confuses many of your fellow programmers. – Adrian McCarthy Jun 01 '11 at 15:48
  • Typically? `gcc -Wall` does not generate a warning for this last I checked; you have to add extra warning options. Surely you can use `UINT_MAX` etc. if you know the type, but the whole point of the problem at hand is to set all bits to 1 when the maximum value is not already known. – R.. GitHub STOP HELPING ICE Jun 01 '11 at 18:42
6

Yes. As mentioned in other answers, -1 is the most portable; however, it is not very semantic and triggers compiler warnings.

To solve these issues, try this simple helper:

static const struct All1s
{
    template<typename UnsignedType>
    inline operator UnsignedType(void) const
    {
        static_assert(std::is_unsigned<UnsignedType>::value, "This is designed only for unsigned types");
        return static_cast<UnsignedType>(-1);
    }
} ALL_BITS_TRUE;

Usage:

unsigned a = ALL_BITS_TRUE;
uint8_t  b = ALL_BITS_TRUE;
uint16_t c = ALL_BITS_TRUE;
uint32_t d = ALL_BITS_TRUE;
uint64_t e = ALL_BITS_TRUE;
Timotheos
  • 405
  • 3
  • 8
  • 6
    As a C programmer, code like this gives me bad dreams at night. – jforberg Aug 25 '15 at 09:26
  • And what happens when you use this in a context like `ALL_BITS_TRUE ^ a` where `a` is a signed integer? The type stays signed integer and the bit-pattern (object representation) depends on the target being 2's complement or not. – Peter Cordes Jul 23 '19 at 21:59
  • No, `ALL_BITS_TRUE ^ a` gives a compile error because `ALL_BITS_TRUE` is ambiguous. It could be used like `uint32_t(ALL_BITS_TRUE) ^ a`, however. You can try it yourself on http://cpp.sh :) Nowadays I'd add a `static_assert(std::is_unsigned::value, "This is designed only for unsigned types");` in the `operator` to be sure users don't try to use `int(ALL_BITS_TRUE)`. I'll update the answer. – Timotheos Jul 25 '19 at 02:17
6

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.

Michael Norrish
  • 412
  • 2
  • 11
  • 1
    the constants you suggested are actually defined in limits.h - stdint.h contains the limits for the additional integers types (fixed-sized integers, intptr_t,...) – Christoph May 03 '09 at 19:27
2

Although the 0xFFFF (or 0xFFFFFFFF, etc.) may be easier to read, it can break portability in code which would otherwise be portable. Consider, for example, a library routine to count how many items in a data structure have certain bits set (the exact bits being specified by the caller). The routine may be totally agnostic as to what the bits represent, but still need to have an "all bits set" constant. In such a case, -1 will be vastly better than a hex constant since it will work with any bit size.

The other possibility, if a typedef value is used for the bitmask, would be to use ~(bitMaskType)0; if bitmask happens to only be a 16-bit type, that expression will only have 16 bits set (even if 'int' would otherwise be 32 bits) but since 16 bits will be all that are required, things should be fine provided that one actually uses the appropriate type in the typecast.

Incidentally, expressions of the form longvar &= ~[hex_constant] have a nasty gotcha if the hex constant is too large to fit in an int, but will fit in an unsigned int. If an int is 16 bits, then longvar &= ~0x4000; or longvar &= ~0x10000; will clear one bit of longvar, but longvar &= ~0x8000; will clear out bit 15 and all bits above that. Values which fit in int will have the complement operator applied to a type int, but the result will be sign extended to long, setting the upper bits. Values which are too big for unsigned int will have the complement operator applied to type long. Values which are between those sizes, however, will apply the complement operator to type unsigned int, which will then be converted to type long without sign extension.

supercat
  • 77,689
  • 9
  • 166
  • 211
2

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.

Akhil Jain
  • 13,872
  • 15
  • 57
  • 93
myron-semack
  • 6,259
  • 1
  • 26
  • 38
2

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.

Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319
  • 1
    Congratulations, you've found a compiler bug! – tc. Dec 10 '12 at 00:36
  • Has this been documented anywhere as a bug? – Nathan Fellman Dec 10 '12 at 06:37
  • 1
    Assuming `UINT64_C(0xffffffff)` expands to something like `0xffffffffuLL`, it is definitely a compiler bug. The C standard largely discusses *values*, the value represented by `0xffffffff` is 4294967295 (not 36893488147419103231), and there aren't any conversions to signed integer types in sight. – tc. Dec 10 '12 at 20:02
2

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.

James Hopkin
  • 13,797
  • 1
  • 42
  • 71
  • In general, we can't be sure about the value of the padding bits. And if we want, then we could be in danger since we could generate a trap representation for them (and it could raise signals). However, the std requires unsigned char to have no padding bits, and in 4.7/2 in the c++ standard says that converting an integer to an unsigned type, the value of the resulting unsigned variable is the smallest value congruent to the source integer value, (modulo 2^n, n==number-of-bits in the unsigned type). then (-1)==((2^n)-1) (mod 2^n) . 2^n-1 has all bits set in a pure binary numbering system. – Johannes Schaub - litb May 12 '09 at 15:50
  • If we *really* want to have all bits 1 in the object representation of an unsigned type, we would need memset. But we could generate a trap representation thereby :( Anyway, an implementation probably has no reason to throw a bit away of their unsigned integers so it will use it to store its values. But you have got a very good point - there is nothing stopping an interpretation from having a few silly nonsense bits, i think (apart of in char/signed char/unsigned char, which must not have those). +1 of course :) – Johannes Schaub - litb May 12 '09 at 15:56
  • In the end, i think the standard could be clearer what representation it refers to in 4.7/2. If it refers to the object representation, then there is no place for padding bits anymore (i have seen people arguing like that which i don't see anything wrong with). But i think it talks about the value representation (because everything in 4.7/2 is about values anyway - and then padding bits may nest next to the value bits. – Johannes Schaub - litb May 12 '09 at 16:08
  • 1
    The Standard seems to pretty clearly have '2’s complement, 1’s complement and signed magnitude' representations in mind, but doesn't want to rule anything out. Interesting point about trapping representations too. As far as I can tell, the bit I quoted is the definition of 'pure binary numeration system' as far as the Standard is concerned - the 'except' bit at the end is really my only doubt over whether casting -1 is guaranteed to work. – James Hopkin May 12 '09 at 16:19
1

As others have mentioned, -1 is the correct way to create an integer that will convert to an unsigned type with all bits set to 1. However, the most important thing in C++ is using correct types. Therefore, the correct answer to your problem (which includes the answer to the question you asked) is this:

std::bitset<32> const flags(-1);

This will always contain the exact amount of bits you need. It constructs a std::bitset with all bits set to 1 for the same reasons mentioned in other answers.

David Stone
  • 26,872
  • 14
  • 68
  • 84
0

I say:

int x;
memset(&x, 0xFF, sizeof(int));

This will always give you the desired result.

Alex
  • 4,122
  • 5
  • 34
  • 40
0

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.

Community
  • 1
  • 1
Antonio
  • 19,451
  • 13
  • 99
  • 197
  • "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" Maybe I'm a bit pedantic here, but the gain of clearness might be questioned here due to the points Johannes mentioned: value vs bit constellation/representation. Someone not quite familiar with bit representation of unsigned integral values (padding bits...) and the standard might have to think twice for this aspect too, as he would have to do for the -1 approach. – Secundi Feb 05 '21 at 09:02
0

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

const auto flags = static_cast<unsigned int>(-1);
FlorianH
  • 600
  • 7
  • 18
0

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.

Secundi
  • 1,150
  • 1
  • 4
  • 12
  • *the best solution at least since C++11 in terms of standard conformity, readability, type safety/explicit clearness and reduction of possible ambiguities* Readability?!?! If that's "readable", I'd hate to see unreadable. – Andrew Henle Feb 05 '21 at 12:29
  • @AndrewHenle, yes, one might question that aspect but I wanted to show the best compromise with respect to all the relevant points. And readability is not just a quantity concern, but also a question about implicity. See for instance, the old C-fashioned "universal" cast style (T)variable is readable at first glance, but readable in terms what's actually going on below the surface? Things are often not that readable as they might occur at first glance in doubt... Maybe I should replace readable with explicitly understandable... – Secundi Feb 05 '21 at 12:37
0

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.

Zifre
  • 26,504
  • 11
  • 85
  • 105
  • 4
    " 0xFF... is not good because it depends on the width of the type" Which is the only sane way to go, I think. You're supposed to define clearly what each flag/bit means in your program. So, if you define that you're using the lowest 32 bits to store flags, you should restrict yourself to use those 32 bits, whether the actual size of the int is 32 or 64. – Juan Pablo Califano Apr 30 '09 at 23:26
0

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.

Drew Hall
  • 28,429
  • 12
  • 61
  • 81
  • 6
    I said that too. But then I realised I was wrong, since -1 signed always converts to max_value unsigned under the conversion rules, regardless of the value representations. At least, it does in C++, I don't have the C standard to hand. – Steve Jessop Apr 30 '09 at 21:51
  • 7
    there is an ambiguity. -1 is not 0xFFFFFFFF. But -1 is 0xFFFFFFFF if converted to an unsigned int (having 32 bits). That's what is making this discussion so difficult i think. Many people have very different things in mind when they talk about those bit strings. – Johannes Schaub - litb Apr 30 '09 at 23:55
  • No. `-1` works everywhere, `~0` will fail on one-complement machines – tstanisl May 05 '21 at 10:16
-6

yes the representation shown is very much correct as if we do it the other way round u will require an operator to reverse all the bits but in this case the logic is quite straightforward if we consider the size of the integers in the machine

for instance in most machines an integer is 2 bytes = 16 bits maximum value it can hold is 2^16-1=65535 2^16=65536

0%65536=0 -1%65536=65535 which corressponds to 1111.............1 and all the bits are set to 1 (if we consider residue classes mod 65536) hence it is much straight forward.

I guess

no if u consider this notion it is perfectly dine for unsigned ints and it actually works out

just check the following program fragment

int main() {

unsigned int a=2;

cout<<(unsigned int)pow(double(a),double(sizeof(a)*8));

unsigned int b=-1;

cout<<"\n"<<b;

getchar();

return 0;

}

answer for b = 4294967295 whcih is -1%2^32 on 4 byte integers

hence it is perfectly valid for unsigned integers

in case of any discrepancies plzz report

  • 9
    Two comments: first, you are dead wrong about the size of integers on “most” machines. Secondly, ur txt iz very hard 2 read due 2 ur us of sum kind of seckrit language. Plz us *plain English*. – Konrad Rudolph Oct 11 '10 at 09:43