8
signed int x = -5;
unsigned int y = x;

What is the value of y? How is this so?

Matthew Smith
  • 508
  • 7
  • 22
sambhav jain
  • 91
  • 1
  • 2
  • 5
    When you tried this, what did you see? – S.Lott Sep 08 '10 at 14:29
  • 4
    @KennyTM, not implementation defined; casting from an unsigned int to a signed int that can't represent it is implementation defined, but the other way around (signed -> unsigned) is well-defined. – bdonlan Sep 08 '10 at 14:35
  • 2
    @bdonlan: `UINT_MAX` *is* implementation defined. – kennytm Sep 08 '10 at 14:37
  • This question is asked to me in an interview.... – sambhav jain Sep 08 '10 at 14:40
  • May you guys please suggest me any book or paper from where i can learn these basic storage and conversion managment concept.... – sambhav jain Sep 08 '10 at 14:42
  • @sambhav jain: Get a C compiler. Write small programs. Explore. – S.Lott Sep 08 '10 at 15:02
  • 1
    @KennyTM: please fix comment that is badly wrong. I can't believe it got +3 upvotes. Any admins able to fix that? – R.. GitHub STOP HELPING ICE Sep 08 '10 at 16:34
  • @R.: What's wrong about it? It depends on UINT_MAX. We know that's at least 65535, but it could be bigger (and usually is, nowadays), and it is implementation-defined. The answer is UINT_MAX - 4. How is that not implementation-defined? – David Thornley Sep 08 '10 at 16:43
  • @David: strictly speaking the value of y is defined by the standard, dependent on something which is implementation-defined. That's not at all the same thing as if the standard said, "the value of y is implemenation-defined", so I'm not sure that "implementation defined" is a correct answer to the question, "what is the value of y?". "Depends on the implementation" would certainly be true, if unhelpful by comparison with KennyTM's actual answesr. – Steve Jessop Sep 08 '10 at 16:51
  • @S.Lott: just what we need, more people who "learn" C by assuming that whatever their compiler does "is C", in preference to following the standard. C is not Python, the language is not defined by an implementation. – Steve Jessop Sep 08 '10 at 16:56
  • 3
    @Steve Jessop: The answer, according to the standard, is UINT_MAX - 4. UINT_MAX is implementation-defined. There is a straight answer, but the numerical one is implementation-defined. – David Thornley Sep 08 '10 at 17:05
  • @Steve Jessop: It's not clear from the question if it's about the standard or an implementation of the standard. Or is it about the fact that the behavior is implementation defined? The questions is vague. Do you know what the question is about? Why would learning a specific implementation -- when confronted with implementation-defined behavior -- be a bad thing? – S.Lott Sep 08 '10 at 17:30
  • 1
    @David: I think that's a misleadingly weaselly definition of implementation-defined behaviour. Implementations don't define the process of converting a signed value to unsigned, and that's what's wrong with KennyTM's comment. – Steve Jessop Sep 08 '10 at 17:30
  • @S.Lott: it doesn't matter whether the question is about the C programming language, or about MSVC 5.0 (or whatever) since the various *useful* answers and comments here get by without needing to know which. It would certainly be a grave tragedy for someone to go away thinking that "in C" (which appears in the question), the result is 65531, because they tried it on one compiler and that's what they got. Anyway if someone asks a question which they *say* is about the C programming language, it seems perverse to second-guess that really they only care about one implementation. – Steve Jessop Sep 08 '10 at 17:37

5 Answers5

17

It depends on the maximum value of the unsigned int. Typically, a unsigned int is 32-bit long, so the UINT_MAX is 232 − 1. The C standard (§6.3.1.3/2) requires a signed → unsigned conversion be performed as

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.

Thus y = x + ((232 − 1) + 1) = 232 − 5 = 4294967291.


In a 2's complement platform, which most implementations are nowadays, y is also the same as 2's complement representation of x.

-5 = ~5 + 1 = 0xFFFFFFFA + 1 = 0xFFFFFFFB = 4294967291.

Community
  • 1
  • 1
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
4

From the C99 standard:

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

49) The rules describe arithmetic on the mathematical value, not the value of a given type of expression.

So you'll be looking at, effectively, y = x + UINT_MAX + 1.

This just happens to mean that the twos-complement representation is used unchanged as an unsigned integer, which makes this very fast on most modern computers, as they use twos-complement for signed integers.

bdonlan
  • 224,562
  • 31
  • 268
  • 324
3

The value of y is UINT_MAX - 5 + 1, i.e. UINT_MAX - 4.

When you convert signed integer value to unsigned type, the value is reduced modulo 2^N, where N is the number of value-forming bits in the unsigned type. This applies to both negative and positive signed values.

If you are converting from signed type to unsigned type of the same size, the above means that positive signed values remain unchanged (+5 gets converted to 5, for example) and negative values get added to MAX + 1, where MAX is the maximum value of the unsigned type (-5 gets converted to MAX + 1 - 5).

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
2

Signed values are typically stored as something called two's complement:

Two's complement numbers are a way to encode negative numbers into ordinary binary, such that addition still works. Adding -1 + 1 should equal 0, but ordinary addition gives the result of 2 or -2 unless the operation takes special notice of the sign bit and performs a subtraction instead. Two's complement results in the correct sum without this extra step.

This means that the actual representation of the numbers -5 and 4294967291 in memory (for a 32 bit word) are identical, e.g: 0xFFFFFFFB or 0b11111111111111111111111111111011. So when you do:

unsigned int y = x;

The contents of x is copied verbatim, i.e. bitwise to y. This means that if you inspect the raw values in memory of x and y they will be identical. However if you do:

unsigned long long y1 = x;

the value of x will be sign-extended before being converted to an unsigned long long. In the common case when long long is 64 bits this means that y1 equals 0xFFFFFFFFFFFFFFFB.

It's important to note what happens when casting to a larger type. A signed value that is cast to a larger signed value will be sign-extended. This will not happen if the source value is unsigned, e.g.:

unsigned int z = y + 5;
long long z1 = (long long)x + 5; // sign extended since x is signed
long long z2 = (long long)y + 5; // not sign extended since y is unsigned

z and z1 will equal 0 but z2 will not. This can be remedied by casting the value to signed before expanding it:

long long z3 = (long long)(signed int)y + 5;

or analogically if you don't want the sign extension to occur:

long long z4 = (long long)(unsigned int)x;
Andreas Magnusson
  • 7,321
  • 3
  • 31
  • 36
  • 1
    But the question is about conversion to *unsigned* type. Yet, in the answer you are only mentioning conversions to *signed* types. – AnT stands with Russia Sep 08 '10 at 15:07
  • I beg to differ, though I do focus my response somewhat on conversions to signed types since that's where there be dragons. I also don't think my response merits the downvote but I'm biased. – Andreas Magnusson Sep 09 '10 at 06:59
  • +1: for "two's complement", even if actually the evasive wording of C99 gives a definition that would also work with a compiler that would use say BCD. I wonder is such C compiler exists anyway, until proved wrong I believe all currently existing C compilers use two's complement. – kriss Sep 09 '10 at 07:33
-1

y=0xfffffffb it's the binary representation of -5 (two's complement)

Philibert Perusse
  • 4,026
  • 5
  • 24
  • 26
  • 1
    The result does not depend on any "binary representation". The result is dictated by the requirements of the language standard. And the standard is rather explicit in this case. – AnT stands with Russia Sep 08 '10 at 14:36
  • @AndreyT. To be fair, although it isn't stated that way, it is certainly true that 2's complement -> unsigned conversion results in the same bit pattern (I think the C++ standard mentions this in passing, can't remember whether the C standard does). Philibert's description is equivalent to the definition in the standard: you can convert signed -> unsigned by working out the 2's complement representation of the signed value, then reading it as an unsigned value. He never said that's how the implementation actually does it (although no doubt 2's complement implementations do). – Steve Jessop Sep 08 '10 at 14:51
  • @Steve Jessop: Well, it is not equivalent to the definition in the standard at least because the standard definition is not limited to conversions between types of the same size, while the "same representation" approach is only applicable when the sizes are the same. – AnT stands with Russia Sep 08 '10 at 15:11
  • @AndreyT: true, it's only equivalent for the case being asked about, it doesn't address other cases at all. I'm more worried about the assumption that `int` is 32 bits. – Steve Jessop Sep 08 '10 at 17:03