Integer promotion and overflow

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

    #16
    Re: Integer promotion and overflow



    Neo wrote:[color=blue]
    > "Michael Mair" <Michael.Mair@i nvalid.invalid> wrote in message
    > news:33s645F40i 738U1@individua l.net...
    >[color=green]
    >>
    >>Neo wrote:
    >>[color=darkred]
    >>>"Keith Thompson" <kst-u@mib.org> wrote in message
    >>>news:ln8y7bm pvu.fsf@nuthaus .mib.org...
    >>>
    >>>
    >>>>Russell Shaw <rjshawN_o@s_pa m.netspace.net. au> writes:
    >>>>
    >>>>
    >>>>>I'm using gcc-3.4.3 on a linux pc. The ints and long ints are 32 bits
    >>>>>and long long ints are 64 bits.
    >>>>>
    >>>>>When i have:
    >>>>>
    >>>>> int num=9600;
    >>>>> long long int reg=(long long)8000000000 00/(5000000*num);
    >>>>>
    >>>>>the denominator overflows and gives an incorrect answer: reg=1059
    >>>>>
    >>>>>With an extra cast:
    >>>>>
    >>>>> long long int reg=(long long)8000000000 00/((long long)5000000*nu m);
    >>>>>
    >>>>>i get: reg=16
    >>>>>
    >>>>>If the numerator is a long long int, should the denominator be
    >>>>>automatica lly promoted to a long long int?
    >>>>
    >>>>The evaluation of an expression is not affected by the context in
    >>>>which it appears. Think of expressions, including their
    >>>>subexpressi ons, as being evaluated bottom-up, not top-down.
    >>>>
    >>>>The right operand of the "/" operator is:
    >>>>
    >>>> (5000000*num)
    >>>>
    >>>>Each operand of the "*" is of type int, so it's an int-by-int
    >>>>multiplicat ion yielding an int result. (It overflows, which invokes
    >>>>undefined behavior, which most likely shows up as discarding the
    >>>>high-order bits.) That int result then becomes the right operand of
    >>>>the "/" operator. The left operand of the "/" operator is (long
    >>>>long)800000 000000, which is of type long long, so the right operand is
    >>>>promoted to long long -- but that promotion (to 64 bits) is done
    >>>>*after* the 32-bit multiplication.
    >>>>
    >>>>Since the overflow invokes undefined behavior, I suppose a
    >>>>sufficientl y clever compiler could let the context affect the
    >>>>evaluatio n of (5000000*num), so the whole expression yields a
    >>>>mathematica lly correct result. But such cleverness doesn't really do
    >>>>you any favors, it merely masks your error.
    >>>>
    >>>>(There are languages in which the context of an expression affects its
    >>>>evaluatio n. C is not such a language.)
    >>>>
    >>>>You might prefer to use a suffix on the integer constants rather than
    >>>>casting them to long long:
    >>>>
    >>>> long long int reg=80000000000 0LL/(5000000LL*num) ;
    >>>
    >>>
    >>>Hi Keith,
    >>>
    >>>I used the following form :
    >>>
    >>>int num = 9600;
    >>>long long int i = (long long)8000000000 00/(5000000LL * num);
    >>>printf("%ld\ n", i);
    >>>
    >>>on my Win XP machine (gcc 3.3.1) gcc flash out the following warning :
    >>>longlong.c : In function `main':
    >>>longlong.c:7 : warning: integer constant is too large for "long" type
    >>>output : 16
    >>>
    >>>and to more surprise when compiling the same code on Solaris Workstation
    >>>with gcc 3.3 warning was the same as above but the result :
    >>>output : 0
    >>>
    >>>WHY IT IS SO??????[/color]
    >>
    >>RTFmanpage (printf):
    >>
    >>The length modifier l specifies _long_, not _long_long_.
    >>If you want to print a long long, use ll:
    >>printf("%lld\ n", i);
    >>
    >>Depending on the byte representation of the number in memory, we may
    >>well arrive at 16 (korrekt) or 0, if erroneously reading only a part
    >>of the bytes belonging to the argument.[/color]
    >
    > Michael, thanks for the correction. It should be obviously "%lld\n".
    > But why the warning??? its still there.[/color]

    I do not know which is "line 7", so I can only guess.
    Probably, you do not invoke gcc in C99 mode -- C89/90 does not
    know the type long long.
    Please post your complete code or try what the compiler does for
    gcc -Wall -O -std=c99 -pedantic


    Cheers
    Michael
    --
    E-Mail: Mine is a gmx dot de address.

    Comment

    • Neo

      #17
      Re: Integer promotion and overflow


      "Keith Thompson" <kst-u@mib.org> wrote in message
      news:ln1xd3knw1 .fsf@nuthaus.mi b.org...[color=blue]
      > "Neo" <timeless_illus ion@yahoo.com> writes:
      > [...][color=green]
      >> I used the following form :
      >>
      >> int num = 9600;
      >> long long int i = (long long)8000000000 00/(5000000LL * num);
      >> printf("%ld\n", i);
      >>
      >> on my Win XP machine (gcc 3.3.1) gcc flash out the following warning :
      >> longlong.c: In function `main':
      >> longlong.c:7: warning: integer constant is too large for "long" type
      >> output : 16[/color]
      >
      > In C99, the type of an unsuffixed decimal integer constant is the
      > first of int, long int, or long long int in which its value can be
      > represented.
      >
      > In C90, there is no type long long int, so the constant is of type
      > long int (which is too small).
      >
      > I think gcc is acting as a C90 compiler as far as determining the
      > types of integer constants is concerned, but is supporting long long
      > as an extension.
      >
      > Try invoking gcc with "-std=c99" and/or use 800000000000LL rather than
      > (long long)8000000000 00.[/color]

      yeah! thnx.
      -Neo
      [color=blue]
      >[color=green]
      >> and to more surprise when compiling the same code on Solaris Workstation
      >> with gcc 3.3 warning was the same as above but the result :
      >> output : 0[/color]
      >
      > Because you're trying to print a long long value, but you're telling
      > printf to expect a long ("%ld"). Use "%lld" to print a long long.
      >
      > --
      > Keith Thompson (The_Other_Keit h) kst-u@mib.org
      > <http://www.ghoti.net/~kst>
      > San Diego Supercomputer Center <*>
      > <http://users.sdsc.edu/~kst>
      > We must do something. This is something. Therefore, we must do this.[/color]


      Comment

      • Keith Thompson

        #18
        Re: Integer promotion and overflow

        "aegis" <aegis@mad.scie ntist.com> writes:[color=blue]
        > Eric Sosman wrote:[color=green]
        >> Russell Shaw wrote:[/color][/color]
        [...][color=blue][color=green][color=darkred]
        >> > If the numerator is a long long int, should the denominator be
        >> > automatically promoted to a long long int?[/color]
        >>
        >> Yes. But the denominator (in the first form) is itself
        >> the product of two factors of type `int', so it is calculated
        >> in `int' arithmetic.[/color]
        >
        > It would seem that 6.4.4.1#5 says that if 5000000 cannot be
        > represented by the type int then it would try long int
        > and if not long int, then long long int.
        >
        > "The type of an integer constant is the first of the
        > corresponding list in which its value can be represented."[/color]

        On the system in question, int and long are both 32 bits, and long
        long is 64 bits. Since 5000000 fits in 32 bits, it's of type int.

        --
        Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
        San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
        We must do something. This is something. Therefore, we must do this.

        Comment

        • aegis

          #19
          Re: Integer promotion and overflow

          is my interpretation correct though?

          for example,

          long long foo = 5000000000;

          if 5000000000 cannot be represented by the type int
          then the compiler sees if it can be represented by type long int
          and if not, then it tries long long int.

          I tried this with gcc invoking -std=c99 and it seems to initialize
          to the correct value but issues a warning. Should it issue
          the warning? If my interpretation is correct then I do not see how this
          warrants a diagnostic.

          --
          aegis

          Comment

          • infobahn

            #20
            Re: Integer promotion and overflow

            aegis wrote:[color=blue]
            >
            > is my interpretation correct though?
            >
            > for example,
            >
            > long long foo = 5000000000;
            >
            > if 5000000000 cannot be represented by the type int
            > then the compiler sees if it can be represented by type long int
            > and if not, then it tries long long int.
            >
            > I tried this with gcc invoking -std=c99 and it seems to initialize
            > to the correct value but issues a warning. Should it issue
            > the warning? If my interpretation is correct then I do not see how this
            > warrants a diagnostic.[/color]

            Conforming C compilers can issue diagnostics for any circumstance
            they like. They are /required/ to issue at least one diagnostic
            if the translation unit contains any syntax errors or constraint
            violations, but the Standard does not stop them issuing diagnostics
            in other circumstances. For example, it's perfectly legal for
            your compiler to diagnose:

            int main(void)
            {
            return 0;
            }

            like this:

            "Fatal error - missing environment division. Format your hard disk."

            This diagnostic is utterly misleading, but perfectly legal. Such a
            compiler wouldn't sell very well, but that's a completely different
            kettle of fish.

            Comment

            • Keith Thompson

              #21
              Re: Integer promotion and overflow

              "aegis" <aegis@mad.scie ntist.com> writes:[color=blue]
              > is my interpretation correct though?
              >
              > for example,
              >
              > long long foo = 5000000000;
              >
              > if 5000000000 cannot be represented by the type int
              > then the compiler sees if it can be represented by type long int
              > and if not, then it tries long long int.
              >
              > I tried this with gcc invoking -std=c99 and it seems to initialize
              > to the correct value but issues a warning. Should it issue
              > the warning? If my interpretation is correct then I do not see how this
              > warrants a diagnostic.[/color]

              I wouldn't expect a warning in that case, but as infobahn points out
              the standard allows a compiler to issue any diagnostic it likes.

              You don't tell us what the warning is, so it's impossible to tell
              what's going on. I tried compiling the above with several versions of
              gcc. More recent versions give a warning

              tmp.c:1: warning: integer constant is too large for "long" type

              without "-std=c99"; none that I tried give a warning with "-std=c99".

              --
              Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
              San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
              We must do something. This is something. Therefore, we must do this.

              Comment

              Working...