Int to Unsigned Int Conversion

int to unsigned int conversion

You can convert an int to an unsigned int. The conversion is valid and well-defined.

Since the value is negative, UINT_MAX + 1 is added to it so that the value is a valid unsigned quantity. (Technically, 2N is added to it, where N is the number of bits used to represent the unsigned type.)

In this case, since int on your platform has a width of 32 bits, 62 is subtracted from 232, yielding 4,294,967,234.

Signed to unsigned conversion in C - is it always safe?

Short Answer

Your i will be converted to an unsigned integer by adding UINT_MAX + 1, then the addition will be carried out with the unsigned values, resulting in a large result (depending on the values of u and i).

Long Answer

According to the C99 Standard:

6.3.1.8 Usual arithmetic conversions

  1. If both operands have the same type, then no further conversion is needed.
  2. Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
  3. Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.
  4. Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.
  5. Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

In your case, we have one unsigned int (u) and signed int (i). Referring to (3) above, since both operands have the same rank, your i will need to be converted to an unsigned integer.

6.3.1.3 Signed and unsigned integers

  1. When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
  2. Otherwise, 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.
  3. Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

Now we need to refer to (2) above. Your i will be converted to an unsigned value by adding UINT_MAX + 1. So the result will depend on how UINT_MAX is defined on your implementation. It will be large, but it will not overflow, because:

6.2.5 (9)

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

Bonus: Arithmetic Conversion Semi-WTF

#include <stdio.h>

int main(void)
{
unsigned int plus_one = 1;
int minus_one = -1;

if(plus_one < minus_one)
printf("1 < -1");
else
printf("boring");

return 0;
}

You can use this link to try this online: https://repl.it/repls/QuickWhimsicalBytes

Bonus: Arithmetic Conversion Side Effect

Arithmetic conversion rules can be used to get the value of UINT_MAX by initializing an unsigned value to -1, ie:

unsigned int umax = -1; // umax set to UINT_MAX

This is guaranteed to be portable regardless of the signed number representation of the system because of the conversion rules described above. See this SO question for more information: Is it safe to use -1 to set all bits to true?

How can an (int) be converted to (unsigned int) while preserving the original bit pattern?

Is it acceptable to cast from (int) to (unsigned)(intN_t) to preserve bit patterns?

Often, yes, but not specified to do so in C for all values. C tries to maintain values during type conversions, not bit patterns.

Should a value, say x, be representable as int, unsigned and the chosen intN_t, then that value's bit pattern does not change. So the question relates to when x is negative.

C specifies that conversion to any unsigned type cope with overflow by add/subtracting the "maximum value of the unsigned type + 1" until the result is in range. Should the signed type use 2's complement encoding, the pattern of lower significant bits will match the target unsigned type.

Conversion to signed integer types in implementation defined behavior - hence OP's dilemma.

C only specifies that the range of a signed integer type and its corresponding unsigned integer type both need to encode the rage: 0 to the signed type maximum. IOWs INT_MAX == UINT_MAX is allowed. On such rare platforms, converting from int to unsigned to int loses the sign.


If code needs to preserve some signed type's bit pattern, a union with an array of unsigned char works in all cases.

union uA {
some_signed_int_type i;
unsigned char uc[sizeof (some_signed_int_type)];
}

A union with a fixed-width unsigned type (these types are optional) whose maximum is greater than the signed maximum works to maintain the bit pattern. Do not rely on the value being the same, even for positive values. Fixed width types do not have padding, not so the general signed types.

assert(uintN_MAX > some_signed_type_max);
union uB {
some_signed_int_type i;
uintN_t u;
}

The central benefit of unsigned char and (u)intN_t is that these types are specified to not have padding.

Automatic conversion of int to unsigned int

You can enable -Wsign-compare -Werror in Clang: Try it online!

It'll produce a compile-time error (because of -Werror that treats warnings as errors):

.code.tio.cpp:7:9: error: comparison of integers of different signs: 'int' and 'unsigned int' [-Werror,-Wsign-compare]
if(x>u) {
~^~
1 error generated.

For some reason, -Wall -Werror in Clang (but not in GCC) doesn't produce any errors. But -Wall -Wextra -Werror does include -Wsign-compare, so you can use that.

Does signed to unsigned casting in C changes the bit values

Conversion from signed int to unsigned int does not change the bit representation in two’s-complement C implementations, which are the most common, but will change the bit representation for negative numbers, including possible negative zeroes on one’s complement or sign-and-magnitude systems.

This is because the cast (unsigned int) a is not defined to retain the bits but the result is the positive remainder of dividing a by UINT_MAX + 1 (or as the C standard (C11 6.3.1.3p2) says,

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.

The two’s complement representation for negative numbers is the most commonly used representation for signed numbers exactly because it has this property of negative value n mapping to the same bit pattern as the mathematical value n + UINT_MAX + 1 – it makes it possible to use the same machine instruction for signed and unsigned addition, and the negative numbers will work because of wraparound.

C++ unsigned and signed conversion

After:

unsigned int u = 10;
int i = -3;

the evaluation of i + u proceeds by first converting i to unsigned int. For a 32-bit unsigned int, this conversion wraps modulo 232, which is 4,294,967,296. The result of this wrapping is −3 + 4,294,967,296 = 4,294,967,293.

After the conversion, we are adding 4,294,967,293 (converted i) and 10 (u). This would be 4,294,967,303. Since this exceeds the range of a 32-bit unsigned int, it is wrapped modulo 4,294,967,296. The result of this is 4,294,967,303 − 4,294,967,296 = 7.

Thus “7” is printed.

Is a type cast necessary while converting between signed int and unsigned int?

Code 1: This conversion is well-defined. If the int is out of range of unsigned int, then UINT_MAX + 1 is added to bring it in range.

Since the code is correct and normal, there should be no warning. However you could try the gcc switch -Wconversion which does produce a warning for some correct conversions, particularly signed-unsigned conversion.

Code 2: This conversion is implementation-defined if the input is larger than INT_MAX. Most likely the implementation you are on defines it to be the inverse of the conversion in Code 1.

Typically, compilers don't warn for implementation-defined code which is well-defined on that implementation. Again you can use -Wconversion.

A cast is not necessary and as a general principle, casts should be avoided as they can hide error messages.

Convert 8 bit signed integer to unsigned and then convert to int32

Here is one possible branch-free conversion:

output = package; // range 0 to 255
output -= (output & 0x80) << 1;

The second line will subtract 256 if bit 7 is set, e.g.:

  • 251 has bit 7 set, 251 - 256 = -5
  • 5 has bit 7 clear, 5 - 0 = 5


Related Topics



Leave a reply



Submit