A trick question

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Gio

    A trick question

    Code:
    short i, j;
    
    i = -32768;
    j = -i;
    
    printf("%d", j);
    As some of you may have guessed by my previous post (about books), I'm
    trying to learn C. Well, a friend of mine (who is a programmer) asked me
    (who is not a programmer) what the output of this would be, and why. I
    had no clue, so I ran it, and it printed -32768. I gave him my best
    guess (which was wrong):
    1) a short maxes out at 32768, so it has no more room to hold the
    sign info. That's it for i, anyway. When you define j as -i, it's
    saying "here's some sign info, then look at i", not actually doing
    the math as -1 * i.
    My second guess was:
    2) There are little gremlins in my compiler changing signs of my
    numbers around. Darn gremlins!
    Okay, so that one was wrong too. :(

    I have to say, I'm a little bothered by this. Why does it print -32768?

    - Gio

    --
    AND NOW FOR A WORD (an IF blog):


  • Ioannis Vranos

    #2
    Re: A trick question

    Gio wrote:
    Code:
    >
    short i, j;
    >
    i = -32768;
    j = -i;
    >
    printf("%d", j);
    >
    >
    As some of you may have guessed by my previous post (about books), I'm
    trying to learn C. Well, a friend of mine (who is a programmer) asked me
    (who is not a programmer) what the output of this would be, and why. I
    had no clue, so I ran it, and it printed -32768. I gave him my best
    guess (which was wrong):
    >
    >1) a short maxes out at 32768, so it has no more room to hold the sign
    >info. That's it for i, anyway. When you define j as -i, it's saying
    >"here's some sign info, then look at i", not actually doing the math
    >as -1 * i.
    >
    My second guess was:
    >
    >2) There are little gremlins in my compiler changing signs of my
    >numbers around. Darn gremlins!
    >
    Okay, so that one was wrong too. :(
    >
    I have to say, I'm a little bothered by this. Why does it print -32768?

    Try the following:

    #include <stdio.h>

    int main(void)
    {
    short i, j;

    i= -32767;

    j= -i;

    printf("%d\n", j);

    i= i- 1;

    j= -i;

    printf("%d\n", j);

    return 0;
    }


    Give us what this program outputs to your system, and try to explain us
    what is happening on each statement.

    Comment

    • Ioannis Vranos

      #3
      Re: A trick question

      The code fixed:


      Ioannis Vranos wrote:
      Gio wrote:
      >
      Code:
      >>
      >short i, j;
      >>
      >i = -32768;
      >j = -i;
      >>
      >printf("%d", j);
      >>
      >
      >>
      >As some of you may have guessed by my previous post (about books), I'm
      >trying to learn C. Well, a friend of mine (who is a programmer) asked me
      >(who is not a programmer) what the output of this would be, and why. I
      >had no clue, so I ran it, and it printed -32768. I gave him my best
      >guess (which was wrong):
      >>
      >>1) a short maxes out at 32768, so it has no more room to hold the sign
      >>info. That's it for i, anyway. When you define j as -i, it's saying
      >>"here's some sign info, then look at i", not actually doing the math
      >>as -1 * i.
      >My second guess was:
      >>
      >>2) There are little gremlins in my compiler changing signs of my
      >>numbers around. Darn gremlins!
      >Okay, so that one was wrong too. :(
      >>
      >I have to say, I'm a little bothered by this. Why does it print -32768?

      Try the following:


      #include <stdio.h>

      int main(void)
      {
      short i, j;

      i= -32767;

      j= -i;

      printf("i= %hd\n", i);

      printf("j= %hd\n\n", j);


      i= i- 1;

      j= -i;

      printf("i= %hd\n", i);

      printf("j= %hd\n", j);


      return 0;
      }



      Give us what this program outputs to your system, and try to explain us
      what is happening on each statement.

      Comment

      • Richard Heathfield

        #4
        Re: A trick question

        Gio said:
        Code:
        >
        short i, j;
        >
        i = -32768;
        j = -i;
        >
        printf("%d", j);
        >
        >
        As some of you may have guessed by my previous post (about books), I'm
        trying to learn C. Well, a friend of mine (who is a programmer) asked me
        (who is not a programmer) what the output of this would be, and why.
        Let's start off by assuming a simpler case, where i is -1, so j takes the
        value 1. Since printf is a variadic function, "the default argument
        promotions are performed on trailing arguments" (as the Standard says), so
        the short int value of 1 is promoted to an int, which matches %d just
        fine. So the problem (and yes, there may be one) is not with the %d.

        Okay, so i = -32768, and that's a problem right there, because it's outside
        the minimum range for short int, which is -32767 to +32767.
        Implementations are free to provide wider ranges, but are not forced to. I
        *guess* that your implementation actually supports -32768 to +32767. If
        I'm right, then what's happening is that the program is trying to assign
        -(-32768), which is +32768, into an object that can't support a value that
        high. The result is undefined, and the Standard doesn't say anything at
        all about what will happen. So whatever gets printed, count yourself lucky
        that you probably didn't catch bubonic plague from this code.

        But why -32768?

        Okay, bearing in mind that the result is undefined so there doesn't even
        have to *be* a reason, let's try to see if we can find one anyway.

        Let's reduce the problem to four bits (a *really* short int).

        You're doing this:

        reallyshort i, j;
        i = -8; /* bit pattern 1000, two's complement */
        j = -i;

        C promotes -8 to an int, and then does a unary minus on it, giving 8.
        Assuming 16-bit ints (and the same argument applies to larger ints), this
        has a bit pattern of 000000000000100 0. If we're going to load this value
        into j (which has only four bits), something has to give, and it's the
        high bits that go, so j gets the value 1000, which is -8!

        Using four bits per reallyshort saved me some typing and counting, but
        precisely the same argument applies to 16-bit shorts, the only difference
        being that a lot more 0s and 1s are involved.

        --
        Richard Heathfield <http://www.cpax.org.uk >
        Email: -http://www. +rjh@
        Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
        "Usenet is a strange place" - dmr 29 July 1999

        Comment

        • Ioannis Vranos

          #5
          Re: A trick question

          Richard Heathfield wrote:
          Gio said:
          >
          >
          Code:
          >>
          >short i, j;
          >>
          >i = -32768;
          >j = -i;
          >>
          >printf("%d", j);
          >>
          >
          >>
          >As some of you may have guessed by my previous post (about books), I'm
          >trying to learn C. Well, a friend of mine (who is a programmer) asked me
          >(who is not a programmer) what the output of this would be, and why.
          >
          Let's start off by assuming a simpler case, where i is -1, so j takes the
          value 1. Since printf is a variadic function, "the default argument
          promotions are performed on trailing arguments" (as the Standard says), so
          the short int value of 1 is promoted to an int, which matches %d just
          fine. So the problem (and yes, there may be one) is not with the %d.
          >
          Okay, so i = -32768, and that's a problem right there, because it's outside
          the minimum range for short int, which is -32767 to +32767.
          Implementations are free to provide wider ranges, but are not forced to. I
          *guess* that your implementation actually supports -32768 to +32767. If
          I'm right, then what's happening is that the program is trying to assign
          -(-32768), which is +32768, into an object that can't support a value that
          high. The result is undefined, and the Standard doesn't say anything at
          all about what will happen. So whatever gets printed, count yourself lucky
          that you probably didn't catch bubonic plague from this code.
          >
          But why -32768?
          >
          Okay, bearing in mind that the result is undefined so there doesn't even
          have to *be* a reason, let's try to see if we can find one anyway.
          >
          Let's reduce the problem to four bits (a *really* short int).
          >
          You're doing this:
          >
          reallyshort i, j;
          i = -8; /* bit pattern 1000, two's complement */
          j = -i;
          >
          C promotes -8 to an int, and then does a unary minus on it, giving 8.
          Assuming 16-bit ints (and the same argument applies to larger ints), this
          has a bit pattern of 000000000000100 0. If we're going to load this value
          into j (which has only four bits), something has to give, and it's the
          high bits that go, so j gets the value 1000, which is -8!
          >
          Using four bits per reallyshort saved me some typing and counting, but
          precisely the same argument applies to 16-bit shorts, the only difference
          being that a lot more 0s and 1s are involved.

          I think a better approach is to let him think what is happening at each
          statement.

          Comment

          • Joe Wright

            #6
            Re: A trick question

            Gio wrote:
            Code:
            >
            short i, j;
            >
            i = -32768;
            j = -i;
            >
            printf("%d", j);
            >
            >
            As some of you may have guessed by my previous post (about books), I'm
            trying to learn C. Well, a friend of mine (who is a programmer) asked me
            (who is not a programmer) what the output of this would be, and why. I
            had no clue, so I ran it, and it printed -32768. I gave him my best
            guess (which was wrong):
            >
            >1) a short maxes out at 32768, so it has no more room to hold the sign
            >info. That's it for i, anyway. When you define j as -i, it's saying
            >"here's some sign info, then look at i", not actually doing the math
            >as -1 * i.
            >
            My second guess was:
            >
            >2) There are little gremlins in my compiler changing signs of my
            >numbers around. Darn gremlins!
            >
            Okay, so that one was wrong too. :(
            >
            I have to say, I'm a little bothered by this. Why does it print -32768?
            >
            - Gio
            >
            Assuming twos complement and short is 16 bits, SHRT_MAX is 32767 or
            0x7fff or 0111_1111_1111_ 1111. SHRT_MIN is -32768 or 0x8000 or
            1000_0000_0000_ 0000.

            In twos complement, to negate a value, we take its ones complement and
            add one to it (Voila, twos).

            Given 1000_0000_0000_ 0000 complementing it we have 0111_1111_1111_ 1111
            and adding one we have 1000_0000_0000_ 0000 again.

            --
            Joe Wright
            "Everything should be made as simple as possible, but not simpler."
            --- Albert Einstein ---

            Comment

            • Walter Roberson

              #7
              Re: A trick question

              In article <wNudnX9Vpezm7Z fVnZ2dnUVZ8qKvn Z2d@bt.com>,
              Richard Heathfield <rjh@see.sig.in validwrote:
              >Okay, so i = -32768, and that's a problem right there, because it's outside
              >the minimum range for short int, which is -32767 to +32767.
              >Implementation s are free to provide wider ranges, but are not forced to. I
              >*guess* that your implementation actually supports -32768 to +32767. If
              >I'm right, then what's happening is that the program is trying to assign
              >-(-32768), which is +32768, into an object that can't support a value that
              >high. The result is undefined, and the Standard doesn't say anything at
              >all about what will happen.
              The situation gets even more complicated, due to the fact that
              C parses -32768 as the unary minus operation applied to 32678 --
              and by previous assumption, 32768 is greater than the maximum
              signed short. Due to a chain of reasons, it is certain to all work out
              for the case of assigning a literal -32768 to a signed int, but

              long i = -2147483648;

              is not certain to work even when signed long can store that value;
              the code may have to be written as

              long i = -2147483647-1;
              --
              "Product of a myriad various minds and contending tongues, compact of
              obscure and minute association, a language has its own abundant and
              often recondite laws, in the habitual and summary recognition of
              which scholarship consists." -- Walter Pater

              Comment

              • CBFalconer

                #8
                Re: A trick question

                Gio wrote:
                >
                Code:
                short i, j;
                >
                i = -32768;
                j = -i;
                >
                printf("%d", j);
                >
                As some of you may have guessed by my previous post (about books),
                I'm trying to learn C. Well, a friend of mine (who is a programmer)
                asked me (who is not a programmer) what the output of this would
                be, and why. I had no clue, so I ran it, and it printed -32768. I
                gave him my best guess (which was wrong):
                Because your system is (obviously) using 16 bits for integers.
                INT_MAX will obviously be 32767 (see limits.h include file) so the
                act of negating -32768 creates an overflow. Now you no longer have
                any control over the program, since the result is either undefined
                or implementation defined.

                If you need portable code and values requiring 32 bits, use a
                long. Then the size is guaranteed. Unsigned things also define
                the action on 'overflow'.

                --
                [mail]: Chuck F (cbfalconer at maineline dot net)
                [page]: <http://cbfalconer.home .att.net>
                Try the download section.


                ** Posted from http://www.teranews.com **

                Comment

                • Gio

                  #9
                  Re: A trick question

                  I had to modify the program to be used by my compiler (it's an old one;
                  I'm doing this on an Apple II)

                  Code:
                  #include <stdio.h>
                  
                  main()
                  {
                  short i, j;
                  
                  i = -32767;
                  j = -i;
                  
                  printf("i = %x\n", i);
                  printf("j = %x\n\n", j);
                  
                  i = i - 1;
                  j = -i;
                  
                  printf("i = %x\n", i);
                  printf("j = %x\n", j);
                  }
                  So, I don't know if the output is what you intended, but here goes:

                  i = 8001
                  j = 7fff

                  i = 8000
                  j = 8000

                  - Gio

                  --
                  AND NOW FOR A WORD (an IF blog):


                  Comment

                  • Richard Heathfield

                    #10
                    Re: A trick question

                    Ioannis Vranos said:
                    Richard Heathfield wrote:
                    <snip>
                    >Using four bits per reallyshort saved me some typing and counting, but
                    >precisely the same argument applies to 16-bit shorts, the only
                    >difference being that a lot more 0s and 1s are involved.
                    >
                    >
                    I think a better approach is to let him think what is happening at each
                    statement.
                    Silly of me - I should have thought of that myself. Your solution to his
                    problem is not only brilliant but also widely applicable. It can be used
                    to answer almost every question asked here, and the only prerequisite on
                    the part of the questioner is a perfect knowledge of C.

                    --
                    Richard Heathfield <http://www.cpax.org.uk >
                    Email: -http://www. +rjh@
                    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
                    "Usenet is a strange place" - dmr 29 July 1999

                    Comment

                    • Ioannis Vranos

                      #11
                      Re: A trick question

                      Gio wrote:
                      I had to modify the program to be used by my compiler (it's an old one;
                      I'm doing this on an Apple II)

                      What compiler and version are you using?



                      %hd did not work? If it didn't, use %d and use the following code instead:



                      #include <stdio.h>

                      int main(void)
                      {
                      short i;

                      i= 32767;

                      printf("i= %hd\n", i);

                      i= i+1;

                      printf("i= %hd\n", i);

                      i= i+1;

                      printf("i= %hd\n", i);


                      return 0;
                      }



                      Show us the output of the program and what you think each statement does.

                      Comment

                      • Gio

                        #12
                        Re: A trick question

                        Well, I'd like to thank you all for your answers. Not sure that I
                        understand them, but I shall study them. :)

                        - Gio

                        --
                        AND NOW FOR A WORD (an IF blog):


                        Comment

                        • Gio

                          #13
                          Re: A trick question

                          What compiler and version are you using?

                          I am using Aztec-C. Its a version of C that's pretty close to but not
                          quite ANSI C.
                          %hd did not work? If it didn't, use %d and use the following code
                          instead:
                          Well.. it didn't give me any errors, but it just printed the same values
                          as %d would.

                          Output:

                          i = 32767
                          i = -32768
                          i = -32767

                          What it looks like to me is that it's turning over, like an odometer.

                          - Gio

                          --
                          AND NOW FOR A WORD (an IF blog):


                          Comment

                          • Keith Thompson

                            #14
                            Re: A trick question

                            CBFalconer <cbfalconer@yah oo.comwrites:
                            Gio wrote:
                            >
                            Code:
                            >short i, j;
                            >>
                            >i = -32768;
                            >j = -i;
                            >>
                            >printf("%d", j);
                            >
                            >>
                            >As some of you may have guessed by my previous post (about books),
                            >I'm trying to learn C. Well, a friend of mine (who is a programmer)
                            >asked me (who is not a programmer) what the output of this would
                            >be, and why. I had no clue, so I ran it, and it printed -32768. I
                            >gave him my best guess (which was wrong):
                            >
                            Because your system is (obviously) using 16 bits for integers.
                            INT_MAX will obviously be 32767 (see limits.h include file) so the
                            act of negating -32768 creates an overflow. Now you no longer have
                            any control over the program, since the result is either undefined
                            or implementation defined.
                            Um, no.

                            By "integers", do you mean type int? Remember that there are several
                            integer types; "int" is just one of them. Yes, the implementation is
                            using 16 bits for integers, but (probably) only for integers of types
                            short and unsigned short.

                            The statement

                            i = -32768;

                            (where i is of type short) will work as long as SHRT_MIN is -32768 or
                            less (i.e., it can fail only if the range of short is exactly -32767
                            to +32767). The constant 32768 is of type short, int, or long,
                            whichever is the first in which it will fit. Negating it yields a
                            value of the same type, which cannot overflow, so you have an
                            expression of some signed integral type with the value -32768.

                            Assigning this to i causes it to be converted to short; this can fail
                            only if, as mentioned above, short's range is exactly -32767 to
                            +32767 (which is unusual for modern systems).

                            Now in this statement:

                            j = -i;

                            if short is 16 bits, the the unary "-" will overflow. The resulting
                            is behavior is undefined. A typical symptom of this undefined
                            behavior is that the value -32768 is assigned to j (given the typical
                            2's-complement implementation with no overflow checking).

                            Now if SHRT_MIN is -32767, then the situation is a bit different, but
                            that can only occur if the implementation uses 1's-complement or
                            sign-and-magnitude, or if uses 2's-commplement and reserves -32768 as
                            a trap represenation (I *think* that's permitted).
                            If you need portable code and values requiring 32 bits, use a
                            long. Then the size is guaranteed. Unsigned things also define
                            the action on 'overflow'.
                            Right. But you can assume that -32768 will fit in 16 bits *if* you
                            don't mind giving up portability to non-2's-complement implementations
                            (which might be a reasonable choice).

                            --
                            Keith Thompson (The_Other_Keit h) <kst-u@mib.org>
                            Nokia
                            "We must do something. This is something. Therefore, we must do this."
                            -- Antony Jay and Jonathan Lynn, "Yes Minister"

                            Comment

                            • Ioannis Vranos

                              #15
                              Re: A trick question

                              Gio wrote:
                              >What compiler and version are you using?
                              >
                              I am using Aztec-C. Its a version of C that's pretty close to but not
                              quite ANSI C.

                              What is the name and version of your operating system? Perhaps we can
                              help you get a more decent compiler.


                              >%hd did not work? If it didn't, use %d and use the following code
                              >instead:
                              >
                              Well.. it didn't give me any errors, but it just printed the same values
                              as %d would.
                              %hd is the proper format specifier for shorts. %d is for ints, %ld is
                              for longs. You should use %hd for shorts.


                              >
                              Output:
                              >
                              i = 32767
                              i = -32768
                              i = -32767
                              >
                              What it looks like to me is that it's turning over, like an odometer.

                              Exactly, in your case it wraps around. You reach the maximum positive
                              value, and then it goes to the least negative value.

                              In C, it is guaranteed that all unsigned integer types wrap around after
                              they reach their maximum value, that is after their maximum value, if
                              you increase their value +1, they get to 0.

                              For signed integer types like short, the behaviour is undefined. In your
                              case it happens to wrap around, but it could provide some other trash
                              value, or something else could happen.


                              ISO C provides a header file <limits.hthat provides the maximum values
                              for each integer type. You can check the web for more info on <limits.h>.

                              Comment

                              Working...