93

I was curious to know what would happen if I assign a negative value to an unsigned variable.

The code will look somewhat like this.

unsigned int nVal = 0;
nVal = -5;

It didn't give me any compiler error. When I ran the program the nVal was assigned a strange value! Could it be that some 2's complement value gets assigned to nVal?

Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
ckv
  • 10,539
  • 20
  • 100
  • 144
  • 1
    My hunch (haven't been able to find it in the standard yet) is that the behavior is technically undefined. Furthermore, I suspect that you'll see what you expect on pretty much any compiler you can find. So while you'll usually see that behavior, it's probably not a good idea to count on it. – sblom Apr 26 '10 at 06:50
  • 6
    It isn't undefined (see *§4.7/2*), but the representation (e.g. 2s complement) isn't mandated by the standard. – Georg Fritzsche Apr 26 '10 at 06:52
  • @gf (et al below), cool. Looks like the behavior is, in fact, explicitly defined to be what you expected, @viswanathan. – sblom Apr 26 '10 at 06:57
  • 3
    The second line is equivalent to `nVal = (unsigned int) -5;`. The cast of `-5` to `unsigned int` is *defined* in 6.3.1.3. The representation in 2s complement is not mandated by the standard but the algorithm to convert to unsigned is: "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." – Pascal Cuoq Apr 26 '10 at 06:59
  • @Pascal: Where did you find that? – Dennis Zickefoose Apr 26 '10 at 07:04
  • 1
    @Pascal: You seem to be referring to C99, but the question is tagged C++. – Georg Fritzsche Apr 26 '10 at 07:17
  • Oops, sorry. I withdraw my comment. I was indeed assuming C99. – Pascal Cuoq Apr 26 '10 at 07:21
  • Two's complement is the only signed integer representation allowed by [C++20](https://en.cppreference.com/w/cpp/language/types) and [C23](https://en.cppreference.com/w/c/language/arithmetic_types). – Steve Ward Feb 10 '23 at 02:47

7 Answers7

78

For the official answer - Section 4.7 conv.integral

"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). —end note ]

This essentially means that if the underlying architecture stores in a method that is not Two's Complement (like Signed Magnitude, or One's Complement), that the conversion to unsigned must behave as if it was Two's Complement.

jp48
  • 1,186
  • 10
  • 17
Dennis Zickefoose
  • 10,791
  • 3
  • 29
  • 38
46

It will assign the bit pattern representing -5 (in 2's complement) to the unsigned int. Which will be a large unsigned value. For 32 bit ints this will be 2^32 - 5 or 4294967291

NullUserException
  • 83,810
  • 28
  • 209
  • 234
Jasmeet
  • 2,324
  • 16
  • 9
  • 2
    Bit's have nothing to do with it. – GManNickG Apr 26 '10 at 06:55
  • 1
    @BenVoigt: Fair enough, I meant it had nothing to do with how bits are interpreted. (That is, the "bits" in the quoted part is just shorthand for `ceil(log_2(x))`.) – GManNickG Oct 08 '12 at 18:34
  • 1
    @GManNickG Bit's (as in, belongs to the bit)? 2's Compliment [(that's very nice of you)](http://grammar.quickanddirtytips.com/compliment-versus-complement.aspx)? GAAAAAAAAAAAAAH! – NullUserException Oct 18 '12 at 19:16
  • 1
    @NullUserException: Haha, I know. Writing "*'s" in place of just "*s" is a terrible habit I've had for a while. As for compliment instead of complement, that's just pure tomfoolery. :) – GManNickG Oct 18 '12 at 19:20
  • 3
    Simplicity is key. This answer has that. (2^32 - 5) explains this behaviour better than quoting the documentation. – dystopiandev Oct 16 '16 at 11:09
5

You're right, the signed integer is stored in 2's complement form, and the unsigned integer is stored in the unsigned binary representation. C (and C++) doesn't distinguish between the two, so the value you end up with is simply the unsigned binary value of the 2's complement binary representation.

perimosocordiae
  • 17,287
  • 14
  • 60
  • 76
4

It will show as a positive integer of value of max unsigned integer - 4 (value depends on computer architecture and compiler).

BTW
You can check this by writing a simple C++ "hello world" type program and see for yourself

Dror Helper
  • 30,292
  • 15
  • 80
  • 129
  • I wrote and checked it thats why i asked the question but i didnt know how the compiler arrived at that positive value. Thanks – ckv Apr 26 '10 at 06:49
  • 7
    Unfortunately with C++, writing programs to test behavior is not always a good idea. For instance, if one tried to test what happens in the case of _signed_ overflow, it will lead to undefined behavior, which is not guaranteed to be the same on every machine/compiler. – Ben Jones Jul 13 '18 at 20:59
2

Yes, you're correct. The actual value assigned is something like all bits set except the third. -1 is all bits set (hex: 0xFFFFFFFF), -2 is all bits except the first and so on. What you would see is probably the hex value 0xFFFFFFFB which in decimal corresponds to 4294967291.

xordon
  • 5,523
  • 4
  • 18
  • 26
Martin
  • 2,956
  • 7
  • 30
  • 59
2

When you assign a negative value to an unsigned variable then it uses the 2's complement method to process it and in this method it flips all 0s to 1s and all 1s to 0s and then adds 1 to it. In your case, you are dealing with int which is of 4 byte(32 bits) so it tries to use 2's complement method on 32 bit number which causes the higher bit to flip. For example:

┌─[student@pc]─[~]
└──╼ $pcalc 0y00000000000000000000000000000101      # 5 in binary
        5                       0x5                     0y101
┌─[student@pc]─[~]
└──╼ $pcalc 0y11111111111111111111111111111010      # flip all bits  
      4294967290      0xfffffffa      0y11111111111111111111111111111010
┌─[student@pc]─[~]
└──╼ $pcalc 0y11111111111111111111111111111010 + 1  # add 1 to that flipped binarry
      4294967291      0xfffffffb      0y11111111111111111111111111111011
Zafeer
  • 79
  • 7
0

In Windows and Ubuntu Linux that I have checked assigning any negative number (not just -1) to an unsigned integer in C and C++ results in the assignment of the value UINT_MAX to that unsigned integer.

Compiled example link.

KeyC0de
  • 4,728
  • 8
  • 44
  • 68