0

Why the following code prints the value of a as -25536 instead of -25535. My guess is that to normalise the short value in the short range it should do 40000-32767 = 7233 and then start from the first range i.e. -32768+7233 = -25535 then where does extra one come from? Why it's -25536?

#include <stdio.h>
int main()
{
    short  int a = 40000;
    printf("%d", a);
    return 0;
}
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
  • 1
    The operation to perform is 65536-40000=-25536 – mouviciel Apr 11 '21 at 14:57
  • 3
    C11 draft standard n1570: *6.3 Conversions 6.3.1.1 Boolean, characters, and integers 6.3.1.3 Signed and unsigned integers [...] 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.* – EOF Apr 11 '21 at 15:03
  • @mouviciel Then what is the operation performed in case of `short unsigned int a = 70000`, because then a will be printed as 4464. Is it `65536-70000` = -4464 and then 0 - (-4464)?` – Sakshi Tanwar Apr 11 '21 at 15:04
  • @EricPostpischil I am using GCC. Then what is the operation performed in case of `short unsigned int a = 70000`, because then a will be printed as 4464. Is it `65536-70000 = -4464 and then 0 - (-4464)?` – Sakshi Tanwar Apr 11 '21 at 15:05
  • 2
    @SakshiTanwar: The conversion is modulo 65536, which means to add or subtract 65536 as many times as necessary to bring the value into range. So 70,000 is converted by subtracting 65,536 once: 70,000−65,536 = 4,464. – Eric Postpischil Apr 11 '21 at 15:07
  • 1
    This is ´equivalent’ to do : while (a > 32768) a-=65536; Same for big negatives while (a < -32767) a+= 65536; . That does not means that it is what the code do. The code just put the 40000 bits into 2bytes(shirt int) then the compiler print this bits as a signed value between -32767 and 32678. – Ptit Xav Apr 11 '21 at 15:10

2 Answers2

2

In the C 2018 standard, 6.3.1.3 3 says conversion to a signed integer type of a value that cannot be represented in the type is implementation-defined. GCC defines the conversion to wrap modulo 2N, where N is the width of the type (the number of bits in the type, including the sign bit).

In the C implementation you are using, short int has 16 bits, so conversion wraps modulo 216 = 65,536. So 40,000 is converted to short int by subtracting 65,536 as many times as needed to produce a value into range (−32,768 to +32,767), which is just once: 40,000−65,536 = −25,536.

Note that the bits for 40,000 in pure binary are 1001 1100 0100 0000 (215 + 212 + 211 + 210 + 26 = 32,768 + 4,096, + 2,048 + 1,024 + 64 = 40,000). When interpreted as two’s complement, the leading bit means −32,768 instead of +32,768, so the interpretation of the same bits in two’s complement is −32,768 + 4,096, + 2,048 + 1,024 + 64 = −25,536. This and the arithmetic properties of two’s complement and binary are related to the reason for GCC’s choice to wrap modulo 2N.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
-1

First of all, the correct code is

printf("%hd", a);

Your compiler would have warned you about the problem if you had enabled its warnings. gcc even gives the solution.


Getting -25,536 is by no means guaranteed. But here's what's happening.

On a little-endian 2's-complement machine with 32-bit int vars, 40000 is stored as the bytes 40 9C 00 00.

On a little-endian 2's-complement machine with 16-bit short vars, the bytes 40 9C represent -25536.

No operation is performed.


The key two your question is two's complement. You should find this earlier Q&A most relevant.

ikegami
  • 367,544
  • 15
  • 269
  • 518