9

Consider the following code to set all bits of x

unsigned int x = -1;

Is this portable ? It seems to work on at least Visual Studio 2005-2010

parapura rajkumar
  • 24,045
  • 1
  • 55
  • 85

4 Answers4

6

Apparently it is:

(4.7) If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type). [Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation).

It is guaranteed to be the largest amount possible for that type due to the properties of modulo.

C99 also allows it:

Otherwise, if the newtype is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the newtype until the value is in the range of the newtype. 49)

Which wold also be the largest amount possible.


Largest amount possible may not be all bits set. Use ~static_cast<unsigned int>(0) for that.

Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
Pubby
  • 51,882
  • 13
  • 139
  • 180
  • Might be in C where I heard not to do this because some compilers treat it differently. Maybe I'm wrong it's been a while since I haven't use my suggestion. – Jesus Ramos Nov 21 '11 at 06:35
  • @Pubby: I don't think it is the correct answer. Does the quotation say that it *set all bits of x*? – Nawaz Nov 21 '11 at 06:39
  • @Nawaz `-1 mod 2^n` is equivalent to `2^32 - 1` which is the largest number. – Pubby Nov 21 '11 at 06:44
  • @Pubby: You didn't understand my question. Does it set all bits of x? The Standard doesn't say that, does it? – Nawaz Nov 21 '11 at 06:46
  • 1
    @Pubby: That's not Nawaz' point. His point is that "largest number" does not necessarily mean "all bits set". – Benjamin Lindley Nov 21 '11 at 06:46
  • @BenjaminLindley: But the question is specifically about `set all bits of x`. Hence my comment. – Nawaz Nov 21 '11 at 06:47
  • 1
    @BenjaminLindley Whoops I miss understood OP's question. No, it doesn't set all bits. – Pubby Nov 21 '11 at 06:47
  • 1
    @Nawaz: Right. I was agreeing with you, and trying to clarify for Pubby. – Benjamin Lindley Nov 21 '11 at 06:48
  • @BenjaminLindley: Oh. I misread your comment. I thought it was directed at me. – Nawaz Nov 21 '11 at 06:51
  • 3
    @Pubby: According to the C99 standard, under no circumstances is `(unsigned something)-1` different from `~(unsigned something)0`. So `-1` is *always* all bits set. See §6.5.3.3 of C99, "If the promoted type is an unsigned type, the expression `~E` is equivalent to the maximum value representable in that type minus `E`." – Dietrich Epp Nov 21 '11 at 08:05
6

The citation-heavy answer:

I know there are plenty of correct answers in here, but I'd like to add a few citations to the mix. I'll cite two standards: C99 n1256 draft (freely available) and C++ n1905 draft (also freely available). There's nothing special about these particular standards, they're just both freely available and whatever happened to be easiest to find at the moment.

The C++ version:

§5.3.2 ¶9: According to this paragraph, the value ~(type)0 is guaranteed to have all bits set, if (type) is an unsigned type.

The operand of ~ shall have integral or enumeration type; the result is the one’s complement of its operand. Integral promotions are performed. The type of the result is the type of the promoted operand.

§3.9.1 ¶4: This explains how overflow works with unsigned numbers.

Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value representation of that particular size of integer.

§3.9.1 ¶7, plus footnote 49: This explains that numbers must be binary. From this, we can infer that ~(type)0 must be the largest number representable in type (since it has all bits turned on, and each bit is additive).

The representations of integral types shall define values by use of a pure binary numeration system49.

49) 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. (Adapted from the American National Dictionary for Information Processing Systems.)

Since arithmetic is done modulo 2n, it is guaranteed that (type)-1 is the largest value representable in that type. It is also guaranteed that ~(type)0 is the largest value representable in that type. They must therefore be equal.

The C99 version:

The C99 version spells it out in a much more compact, explicit way.

§6.5.3 ¶3:

The result of the ~ operator is the bitwise complement of its (promoted) operand (that is, each bit in the result is set if and only if the corresponding bit in the converted operand is not set). The integer promotions are performed on the operand, and the result has the promoted type. If the promoted type is an unsigned type, the expression ~E is equivalent to the maximum value representable in that type minus E.

As in C++, unsigned arithmetic is guaranteed to be modular (I think I've done enough digging through standards for now), so the C99 standard definitely guarantees that ~(type)0 == (type)-1, and we know from §6.5.3 ¶3 that ~(type)0 must have all bits set.

The summary:

Yes, it is portable. unsigned type x = -1; is guaranteed to have all bits set according to the standard.

Footnote: Yes, we are talking about value bits and not padding bits. I doubt that you need to set padding bits to one, however. You can see from a recent Stack Overflow question (link) that GCC was ported to the PDP-10 where the long long type has a single padding bit. On such a system, unsigned long long x = -1; may not set that padding bit to 1. However, you would only be able to discover this if you used pointer casts, which isn't usually portable anyway.

Community
  • 1
  • 1
Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
5

I was sloppy in reading the question, and made several comments that might be misleading because of that. I'll try to clear up the confusion in this answer.

The declaration

unsigned int x = -1;

is guaranteed to set x to UINT_MAX, the maximum value of type unsigned int. The expression -1 is of type int, and it's implicitly converted to unsigned int. The conversion (which is defined in terms of values, not representations) results in the maximum value of the target unsigned type.

(It happens that the semantics of the conversion are optimized for two's-complement systems; for other schemes, the conversion might involve something more than just copying the bits.)

But the question referred to setting all bits of x. So, is UINT_MAX represented as all-bits-one?

There are several possible representations for signed integers (two's-complement is most common, but ones'-complement and sign-and-magnitude are also possible). But we're dealing with an unsigned integer type, so the way that signed integers are represented is irrelevant.

Unsigned integers are required to be represented in a pure binary format. Assuming that all the bits of the representation contribute to the value of an unsigned int object, then yes, UINT_MAX must be represented as all-bits-one.

On the other hand, integer types are allowed to have padding bits, bits that don't contribute to the representation. For example, it's legal for unsigned int to be 32 bits, but for only 24 of those bits to be value bits, so UINT_MAX would be 2*24-1 rather than 2*32-1. So in the most general case, all you can say is that

unsigned int x = -1;

sets all the value bits of x to 1.

In practice, very very few systems have padding bits in integer types. So on the vast majority of systems, unsigned int has a size of N bits, and a maximum value of 2**N-1, and the above declaration will set all the bits of x to 1.

This:

unsigned int x = ~0U;

will also set x to UINT_MAX, since bitwise complement for unsigned types is defined in terms of subtraction.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Very nice! It turns out that the standards define bitwise complement in terms of subtraction, so it is guaranteed that `~0U == -1` on all systems. – Dietrich Epp Nov 21 '11 at 08:14
1

Beware!

This is implementation-defined, as how a negative integer shall be represented, whether two's complement or what, is not defined by the C++ Standard. It is up to the compiler which makes the decision, and has to document it properly.

In short, it is not portable. It may not set all bits of x.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • @Nawaz... what about Pubby's answer ?... BTW i didn't downvote – parapura rajkumar Nov 21 '11 at 06:37
  • @parapurarajkumar: His answer is wrong. Also, the quotation doesn't say that it *set all bits of x*, does it? – Nawaz Nov 21 '11 at 06:39
  • 2
    It is not implementation-defined. – Keith Thompson Nov 21 '11 at 06:55
  • @KeithThompson: I think, you're getting it wrong. Would it set all bits of x? Retaining the value, and setting all bits of x, is two different thing! – Nawaz Nov 21 '11 at 07:07
  • @Nawaz.. Are you claiming that if `x = std::numeric_limits::max();` ...all bits of x may not be set ? – parapura rajkumar Nov 21 '11 at 07:34
  • @Nawaz: It's guaranteed to set `x` to `INT_MAX`, but I see that that's not what the question was about. It's *almost* guaranteed to set `x` to all-bits-one; see the answer I just posted. – Keith Thompson Nov 21 '11 at 07:38
  • @Nawaz: Keith Thompson is right. The standard is quite clear on how unsigned arithmetic works, including overflow. `-1` is absolutely guaranteed to set all bits to one. – Dietrich Epp Nov 21 '11 at 08:10
  • @DietrichEpp: Quote the Standard where it gives guarantee that `unsigned int x = -1` will set all bits to one? Probably you didn't read what Keith said. Keith didn't say what you think he said. He said `almost`. If it is "almost", it is NOT gauranteed by the Standard. **Also, how do you parameterize "almost"? Does it mean all bits except one will be set to one? Or what?** – Nawaz Nov 21 '11 at 08:18
  • @Nawaz: Sorry, I cited it elsewhere and didn't want to spam the thread. I was also responding to Keith Thompson's earlier comment which does not use the word "almost". Here's the C99 version: §6.5.3.3 of C99, "If the promoted type is an unsigned type, the expression ~E is equivalent to the maximum value representable in that type minus E." If you want to dig up same language in other standards, be my guest. – Dietrich Epp Nov 21 '11 at 08:21
  • @DietrichEpp: You're doing the committing the same mistake, as many did before, in this topic. Maximum value doesn't mean that all the bits are set to one! – Nawaz Nov 21 '11 at 08:22
  • @Nawaz: I really don't want to have to dissect the entire standard for you. From the same paragraph of the C99 standard, "The result of the ~ operator is the bitwise complement of its (promoted) operand (that is, each bit in the result is set if and only if the corresponding bit in the converted operand is not set)." Put the two together and you get `(unsigned)-1` has all bits set. – Dietrich Epp Nov 21 '11 at 08:26