32

Possible Duplicate:
signed to unsigned conversion in C - is it always safe?

Let's say I declare a variable of type unsigned int : unsigned int x = -1;

Now -1 in two's complement (assuming 32 bit machine) is 0xFFFFFFFF. Now when I assigned this value to x, did the value 0x7FFFFFFF get assigned to x?

If it were so, then printf ("%d",x); would have printed the decimal equivalent of 0x7FFFFFFF, right? But, clearly this isn't happening, as the value that gets printed is -1. What am I missing here?

Edit: I know that we can use the %u format specifier to print unsigned values. But that doesn't help answer the question above.

Community
  • 1
  • 1
n0nChun
  • 720
  • 2
  • 8
  • 21
  • 2
    Where did `0x7FFFFFFF` come from? – Evan Mulawski Aug 22 '11 at 19:48
  • @Evan: Flipping the MSB. Just a guess, since I don't know how the conversion really happens – n0nChun Aug 22 '11 at 19:59
  • Section 6.3.1.3 of the C99 standard should answer your question. But this should answer your question a little better http://stackoverflow.com/questions/50605/signed-to-unsigned-conversion-in-c-is-it-always-safe – Joe Aug 22 '11 at 20:16

3 Answers3

42

The "%d" format is for (signed) int values. If you use it with an unsigned value, it could print something other than the actual value. Use "%u" to see the actual value, or %x to see it in hexadecimal.

In the declaration

unsigned int x = -1;

the expression -1 is of type int, and has the value -1. The initializer converts this value from int to unsigned int. The rules for signed-to-unsigned conversion say that the value is reduced modulo UINT_MAX + 1, so -1 will convert to UINT_MAX (which is probably 0xffffffff or 4294967295 if unsigned int is 32 bits).

You simply cannot assign a negative value to an object of an unsigned type. Any such value will be converted to the unsigned type before it's assigned, and the result will always be >= 0.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • But Keith, then, 0x FF FF FF FF has MSB 1, which is used to denote negative numbers, right? Then what have we really gained by assigning a negative value to a variable of type unsigned int? – n0nChun Aug 22 '11 at 20:03
  • 3
    @n0nChun: That's not the only way negative numbers can be represented. 2's-complement is the most common method; others are 1s'-complement and sign-and-magnitude (all three are permitted by the C standard). And the point is that you literally *cannot* assign a negative value to an unsigned int; any negative value will be implicitly converted, resulting in a non-negative unsigned value. Furthermore, `unsigned int` isn't necessarily 32 bits; it can be as small as 16 bits. `-1` will always convert to `UINT_MAX`, which isn't necessarily `0xffffffff`. – Keith Thompson Aug 22 '11 at 20:30
  • @n0nChun the MSB is not used to denote negative numbers in unsigned ints. if you use `%u`, you will see 2 * 0x7fffffff. The maximum for unsigned ints is 2 times larger. – Daniel Aug 22 '11 at 20:34
  • 2
    @Daniel: 2 times as large *plus 1*. – Keith Thompson Aug 22 '11 at 20:52
  • 1
    @keith Thanks for the correction. Because there is no need for +/- 0, there is one more negative number than positive number. Each negative number maps to an unsigned number, so that's where the +1 comes from. – Daniel Aug 22 '11 at 21:51
  • @DevSolar: Fixed, thanks! – Keith Thompson Apr 06 '16 at 15:44
  • If i write `signed int a = -1` , then ` -1` in 2's complement form is `11111111 11111111 11111111 11111111` and then when i use %d to interpret it it prints `-1` and `%u` , it prints `4294967295` and when i write` signed int a = 2` , it prints `2` when i use %d and also when i use %u . If 2 would be in two's complement it would be `11111111 11111111 11111111 11111101` , and then it would be a very diffr answer , what i really want to ask is when does`2's complement` happen is it depend on - sign or it happens for every integer if type is signed int which must not be the case here. – Suraj Jain Dec 30 '16 at 06:57
  • @SurajJain: I don't understand the question. – Keith Thompson Dec 30 '16 at 07:42
  • Sir , what i am asking is when does 2's complement happen ?? In all negative values , when suppose i write signed int a = -2 , it will be stored in 2's complement form , when i write signed int a = 3 , does 2 complement happen then also ? I have couple of things ... if you could clear my doubt it would be of a very great help to me – Suraj Jain Dec 30 '16 at 08:34
  • @SurajJain: I still don't understand what you're asking. 2's complement is a representation. It isn't something that "happens". – Keith Thompson Dec 30 '16 at 17:11
  • @KeithThompson When you say signed int do you mean only variable or constant too ? I think i am confused in this. – Suraj Jain Dec 30 '16 at 17:33
  • @SurajJain: `signed int` is a type. If you have a question, post it as a question. Comments are not for long discussions. – Keith Thompson Dec 30 '16 at 17:36
  • If the value is converted first , why does in the assembly code it is not reflected ? – Suraj Jain Dec 30 '16 at 18:10
  • @SurajJain: If you have a question, post it as a question. Comments are not for long discussions. – Keith Thompson Dec 30 '16 at 19:54
  • @KeithThompson http://stackoverflow.com/questions/41399092/how-does-in-assembly-does-assigning-negative-number-to-an-unsigned-int-work/41402291#41402291 – Suraj Jain Dec 31 '16 at 02:37
6

Use %u instead of %d in order to print unsigned values. Then you should see 0xFFFFFFFF.

Eran Zimmerman Gonen
  • 4,375
  • 1
  • 19
  • 31
  • I know that but doesn't answer my question – n0nChun Aug 22 '11 at 19:54
  • 1
    Assigning -1 to an unsigned int does not just remove the sign bit (0x7FF...) it will still be 0xFF..., use this `printf("%1$u : 0x%1$X\n", x);` to see for your self. – Joe Aug 22 '11 at 19:57
  • 1
    `x = -1` and `x = 0xFFFFFFFF` should yield the same thing. `x = 0x7FFFFFFF` is a different value, and you won't get it from any of the above assignments. If this still doesn't clarify it, then I'm not sure what else you're asking... – Eran Zimmerman Gonen Aug 22 '11 at 19:59
  • 1
    Forget that you've got an unsigned int, and just think of it as a space in memory. When you assigned your variable to -1, what you're really saying is store the value of the signed int -1 to this space in memory. Then with printf, %d is asking it to read a signed int from that space in memory. Both of these are consistent so you'll get back a -1. Your space in memory could be a variable of any type and you'll still see "-1". – asc99c Aug 22 '11 at 20:15
  • @asc99c - While your printf '%d' explanation is correct your assignment is not. The C99 specification actually specifies the behavior for this, it is not just simple memory assignment. *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.* – Joe Aug 22 '11 at 20:28
  • @Joe, No, asc99c is correct. The section of the standard you've quoted applies to *conversions* to unsigned type. `printf("%d", x);` does *not* perform a conversion (because `printf` is variadic, so the expected type is not visible to the compiler); it (probably) performs type-punning, treating a chunk of memory containing an unsigned value as if it contained a signed value. It just happens that this conversion typically works by reinterpreting the representation as a different type. Consider `printf("%d", 1.0);`. If that performed a conversion, it would print `1`. – Keith Thompson Aug 23 '11 at 00:04
  • @Keith Thompson - That is why I said "While your printf '%d' explanation is correct your assignment is not" because I know that `%d` will look at the memory but the actual assignment of `unsigned int x = -2` is were the conversion would take place. – Joe Aug 23 '11 at 01:24
  • Ahh didn't know that bit, the ANSI standard says the same thing. A test program to hex dump the signed and unsigned memory locations appears to show that the result is that the memory location holds the same bytes in either case. – asc99c Aug 23 '11 at 08:04
  • @Joe Can you answer this question ? http://stackoverflow.com/questions/41399092/how-does-in-assembly-does-assigning-negative-number-to-an-unsigned-int-work – Suraj Jain Dec 30 '16 at 17:35
3

What is happening is that you convert the value first to unsigned int, assigning 0xffffffff to x. Then using printf("%d\n") you will convert the value back to signed int still keeping the value of 0xffffffff. Thus printing -1.

Rickard
  • 7,239
  • 1
  • 18
  • 11
  • 3
    Close, but not quite. He *converts*, not *casts* the value (the conversion is implicit, not done via a cast operator). And the `printf` call doesn't perform a type conversion; rather, it probably interprets the representation of the unsigned value as if it were a signed value (type-punning). (Strictly speaking the behavior of the `printf` call is undefined.) – Keith Thompson Aug 22 '11 at 19:56
  • 1
    Yes you are right, I'm using the wrong word. Looking at the asm output from gcc will show two mov, resulting in just interpretation of the value. – Rickard Aug 22 '11 at 19:57