Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

converting -1 to unsigned types

Tags:

c++

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

like image 721
parapura rajkumar Avatar asked Nov 21 '11 06:11

parapura rajkumar


People also ask

How do I convert to unsigned?

To convert a signed integer to an unsigned integer, or to convert an unsigned integer to a signed integer you need only use a cast. For example: int a = 6; unsigned int b; int c; b = (unsigned int)a; c = (int)b; Actually in many cases you can dispense with the cast.

How do I convert an int to unsigned?

1) Add UINT_MAX + 1 to your signed number and store it in an unsigned variable. (this will convert the signed integer to an unsigned integer of same magnitude). 2) Unsigned number of same binary representation can be found by multiplying each digit in the binary representation by its place value and adding them up.

When should you use an unsigned type?

Unsigned integers are used when we know that the value that we are storing will always be non-negative (zero or positive). Note: it is almost always the case that you could use a regular integer variable in place of an unsigned integer.

What is a unsigned data type?

An unsigned data type simply means that the data type will only hold positive values; negatives aren't allowed to be stored in the data type. Unsigned data types include int, char, short, and long.


1 Answers

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.

like image 89
Dietrich Epp Avatar answered Oct 23 '22 08:10

Dietrich Epp