2

Just double checking. On some tutorial I found such code:

#include <iostream>
using namespace std;

/* This program shows the difference between
 * signed and unsigned integers.
*/
int main()
{
   short int i;           // a signed short integer
   short unsigned int j;  // an unsigned short integer

   j = 50000;

   i = j;
   cout << i << " " << j;

   return 0;
}

output: -15536 50000

Then it explains the output: "The above result is because the bit pattern that represents 50,000 as a short unsigned integer is interpreted as -15,536 by a short."

I think this is a wrong explanation - or it is an English issue? I think the reason negative value is output is that 50000 didn't fit in the 2 byte signed int, am I wrong?

user2864740
  • 60,010
  • 15
  • 145
  • 220
  • 2
    The sign is a bit. 50k uses all 16 bits in an unsigned. When it's converted to signed the high bit is the sign and the 15 other bits are 15,536. – Brian Roach Apr 14 '14 at 21:16
  • 1
    "a short" is "the 2 byte signed int". – AntonH Apr 14 '14 at 21:17
  • not following the answers. If I assign 30000 to i, it displays 30000-but since 50000 doesn't fit in signed short, hence the negative value isn't it? (as opposed to the explanation give on the site) –  Apr 14 '14 at 21:19
  • see edit to my comment. 30k fits in 15 bits. – Brian Roach Apr 14 '14 at 21:20
  • http://stackoverflow.com/questions/621290/what-is-the-difference-between-signed-and-unsigned-variables – Matt Apr 14 '14 at 21:20
  • I think people don't understand what I mean here. I am opposing the reason given on the site, which seemingly suggests that if I had assigned any value to i, it would be printed as negative - which is not the case for i=30000 for example –  Apr 14 '14 at 21:22
  • 1
    I don't see where what you've quoted suggests that at all. 16 bits is 16 bits. If the high bit is set, which it is when the number is over 32768 then the number will be negative if it's signed. It says the bit pattern for 50k is interpreted as `-15,536` which is the case. The bits haven't changed; only the interpretation of them. – Brian Roach Apr 14 '14 at 21:26
  • @BrianRoach: it doesn't highlight that the number is incorrectly displayed *because* it overflowed short int. Had it been in the range of short int, it would be displayed correctly right? –  Apr 14 '14 at 21:28

6 Answers6

3

your answer and the books answer are correct

50000 = 0xc350

a signed 16 bit short containing 0xc350 is interpreted as -15,536

So they are correct (interpretation of bit pattern)

if i was a 32 bit int then putting 0xc350 in it would be interpretted as 50,000

so you are correct (I too small)

pm100
  • 48,078
  • 23
  • 82
  • 145
  • i=30000 is not printed as negative. I said 50000 is printed as negative because it doesn't fit in short int, am I wrong? –  Apr 14 '14 at 21:24
  • @dmcr_code The bit pattern fits in a short int, it just means something different. – Radiodef Apr 14 '14 at 21:55
  • re "a signed 16 bit short containing 0xc350 is interpreted as -15,536", that depends on whether the signed short uses two's complement form, one's complement form or sign-and-magnitude. – Cheers and hth. - Alf Apr 14 '14 at 22:59
3

The reasoning in the explanation is perhaps accurate for a specific platform, but in my opinion its irrelevant to what is ultimately printed. It would be far more accurate to say

"The above result is because the bit pattern returned from an implementation-defined conversion of an unsigned short int value of 50000 to a signed short int results in a value of -15,536."

Not shockingly, sending said-value to std::cout will produce the proper output for the signed short int result of said-value. The source of the change (the conversion) is important, and in this case it is implementation-defined. Their phrasing is weak, and the identical statement could be applied by assigning any value to any integral value, so in reality their explanation is ultimately pointless.


Not wanting to waste the previous answer (before I understood the question better), enjoy some light reading. To know for sure why this is happening you must consult your implementation documentation for conversion of this nature. Not the answer you likely want to hear, but there is reason behind it.

This is happening because of value promotion via integer conversion rank. The value you received is, in fact, implementation-dependent, and the specific reason for why are covered in the standard.

I'll leave out the most basic stuff and just get to the meat of it:

C++11 §4.7 Integral promotions [conv.integral]

  1. A prvalue of an integer type can be converted to a prvalue of another integer type. A prvalue of an unscoped enumeration type can be converted to a prvalue of an integer type.

  2. 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 ]

  3. If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined.

  4. If the destination type is bool, see 4.12. If the source type is bool, the value false is converted to zero and the value true is converted to one.

  5. The conversions allowed as integral promotions are excluded from the set of integral conversions.

The value 50000 cannot be represented in a signed short int on your platform. Therefore the results are implementation-defined. By the looks of it your implementation just stores the bytes from one to the other, the result being the sign-bit (also covered in the standard but left out for brevity) is lit and the reported number is negative. Remember, though, this is implementation defined and you cannot rely on this result on all platforms.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • And... I just realized this was posted as C++, so I'm dropping this until/if/when I get the time to find the related standard section in C++. Sorry about that. – WhozCraig Apr 14 '14 at 21:37
  • @WhosCraig: Thanks - but that was not what I asked. I was not looking for reasons why I got negative value, I also thought it would be implementation defined - I merely had problems with the reasons the tutorial gave about printing the negative value (see question). But thanks for nice explanation anyway!! –  Apr 14 '14 at 21:39
  • My main concern was that one could think - from that explanation on tutorial - that any unsigned value converted to int would be interpreted and printed as negative, isn't it?(if j fit in short int, the number would be printed as it is) –  Apr 14 '14 at 21:58
  • ok I'll accept this one since we acknowledge smth is not right with explanation on tutorial ... ps. I'll read more on signed/unsigned int promotions etc. for future. Thanks all for input. –  Apr 14 '14 at 22:05
  • @dmcr_code If I understood that two comments-ago, *yes*. if the *value* promotion fit (i.e. since it is `unsigned` if it were in 0...32767 on your platform, no implementation-dependence would ensue and the value would simply be assigned unchanged. – WhozCraig Apr 14 '14 at 22:08
1

First, integral types are required to be represented using a pure binary system, and so far the tutorial is correct.

Second, a short is required to be at least 16 bits. If it's more, then you won't see the effect that you did, or any effect. It's unclear from your description whether the tutorial blindly assumes that short is necessarily 16 bits (wrong), or whether it's just using some concrete example, with the understanding that it depends on compiler etc.

Third, the conversion to signed type … is formally Implementation Defined Behavior if the value cannot be represented. This means that you are not guaranteed a change of value. Instead you can, in principle, get any effect, such as a crash.

[example of other behavior lacking because I'm unable to cajole g++ 4.8.2 into trapping for your example code, even with -ftrapv]

… yields a value that's either the same, if it can be represented, or otherwise defined by the implementation.

That said, C++ guarantees that unsigned arithmetic is performed modulo 2n, where n is the number of value representation bits, e.g. 16 in your example. And with the very common two's complement form representation of signed integers, a negative integer value -x is represented as the bitpattern for -x + 2n. So if you start with the latter value (the interpretation of the bitpattern as unsigned) as 50 000, with 16 value bits and two's complement form, you get the signed value 50 000 - 216 = 50 000 - 65 536 = -15 536

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
0

50,000 is represented in binary as - 1100 0011 0101 0000.

In a signed bit, the leftmost bit is the sign. In a signed integer, a '0' would represent a negative(hence the -15536), where in an unsigned integer this would make no difference. As for why the number itself changed, I have no idea.

ChengDuum
  • 77
  • 6
0

You are correct and the book is also correct. An unsigned short can have values from 0 to 65535. A signed short can have values from -32768 to 32767. Therefore, any value between 0 and 32767 works for both signed and unsigned.

However, a number like 50000 is too big for a signed short, so when you assign 50000 to a signed short, it causes numeric overflow.

user3386109
  • 34,287
  • 7
  • 49
  • 68
  • Your last sentence is what I meant - and hence why negative value is displayed right? Just it was not specifically mentioned on the tutorial I think that's it (I said could have been an English issue) –  Apr 14 '14 at 21:35
  • Yes, I think it's mostly just an English issue. Any value from 32768 to 65535 is too big for a `signed short`, so assigning those values will cause an overflow, which on most systems will end up being displayed as a negative number. – user3386109 Apr 14 '14 at 21:40
  • yes the author didn't say if the value had fit in i then the value would be displayed properly. –  Apr 14 '14 at 21:42
  • 1
    That's true, the author was just giving one example where the number was too big, instead of explaining how the numbers work in general. I agree that the author could have done a better job. – user3386109 Apr 14 '14 at 21:45
0

An unsigned short is a 16-bit value that doesn't use a sign bit — all values are assumed to be positive.

The decimal value 50,000 stored in binary is

1100 0011 0101 0000
^

The leftmost bit (Most Significant Bit - MSB) is 1 and represents 2^15 which is 32,768

The whole bit pattern is 32,768 + 16,384 + 512 + 256 + 64 + 16 = 50,000

When you cast this to a signed short, the bit pattern is not changed, but the MSB no longer represents 32,768 — it now represents the sign of the number, and the remaining bits are the 2's-complement of the value. In a signed value, that top bit is the sign, and 1 is negative.

This doesn't happen with 30,000 because that is

0111 0101 0011 0000
^

When this is converted to signed the left-most 0 represents the sign, and 0 is positive so the rest of the bits are still interpreted as they are, not as a 2's-complement, and they therefore still represent the same value of 30,000

Stephen P
  • 14,422
  • 2
  • 43
  • 67
  • note that `short` in general can be more than 16 bits. also note, that while 2's complement is the most common representation of signed integers today, it's not the only representation permitted by the C++ standard. – Cheers and hth. - Alf Apr 14 '14 at 23:02
  • @Cheers - I absolutely understand that, having a long history with allegedly portable non-portable-C that I had to make _actually_ portable. I didn't check the official C++ standard but [this page](http://en.cppreference.com/w/cpp/language/types) implies the standard is (at least) 16 bits, and in practice is generally 16 bits. I was trying to explain as clearly as possible based on the actual facts of the OPs experience. – Stephen P Apr 15 '14 at 00:31
  • @StepenP: unfortunately you won't find the size info in "the official C++ standard". it comes from the C standard's value range requirements. the C standard is "incorporated" into the C++ standard. – Cheers and hth. - Alf Apr 15 '14 at 01:07