Integer Promotion?

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

    Integer Promotion?

    I set about trying to find a portable way to set the value of UCHAR_MAX. At
    first, I thought the following would work:

    #define UCHAR_MAX ~( (unsigned char)0 )


    However, it didn't work for me. Could someone please explain to me what's
    going on? I would have thought that the following happens:

    (1) The literal, 0, whose type is int, gets converted to an unsigned char.

    0000 0000

    (2) The resultant unsigned char then has all its bits flipped.

    1111 1111


    My hunch is that there's some sort of integer promotion at work, but I
    don't know exactly how it works.

    Could someone please enlighten me?


    --

    Frederick Gotham
  • Mark Odell

    #2
    Re: Integer Promotion?


    Frederick Gotham wrote:[color=blue]
    > I set about trying to find a portable way to set the value of UCHAR_MAX. At
    > first, I thought the following would work:
    >
    > #define UCHAR_MAX ~( (unsigned char)0 )[/color]

    What's wrong with the version in limits.h?

    Comment

    • Ben Pfaff

      #3
      Re: Integer Promotion?

      Frederick Gotham <fgothamNO@SPAM .com> writes:
      [color=blue]
      > I set about trying to find a portable way to set the value of UCHAR_MAX. At
      > first, I thought the following would work:
      >
      > #define UCHAR_MAX ~( (unsigned char)0 )
      >
      >
      > However, it didn't work for me. Could someone please explain to me what's
      > going on?[/color]

      The operand of ~ is subject to the integer promotions, which
      means that the `unsigned char' value 0 is converted to int (or,
      possibly, to unsigned int) before the complement happens.

      An expression with the right value is (unsigned char) -1, but
      that's not suitable for UCHAR_MAX because it contains a cast and
      because it has the type unsigned char, whereas UCHAR_MAX should
      have type int (or, possibly, unsigned int).
      --
      "I don't have C&V for that handy, but I've got Dan Pop."
      --E. Gibbons

      Comment

      • Lew Pitcher

        #4
        Re: Integer Promotion?

        -----BEGIN PGP SIGNED MESSAGE-----
        Hash: SHA1

        Frederick Gotham wrote:[color=blue]
        > I set about trying to find a portable way to set the value of UCHAR_MAX. At
        > first, I thought the following would work:
        >
        > #define UCHAR_MAX ~( (unsigned char)0 )
        >
        >
        > However, it didn't work for me.[/color]

        First off, why are you trying to /set/ a value that is (or should be)
        supplied to you by your C implementation? Are you just trying to
        second-guess your compiler, or are you trying to change the limit that
        the compiler imposes. FWIW, that manifest constant is (or should be)
        defined by the compiler, and externalized for your information only.

        Secondly, what do you mean by "it didn't work for me". What did you get?
        What did you expect to get? How did the #define fail you?

        [snip]


        - --

        Lew Pitcher, IT Specialist, Corporate Technology Solutions,
        Enterprise Technology Solutions, TD Bank Financial Group

        (Opinions expressed here are my own, not my employer's)
        -----BEGIN PGP SIGNATURE-----
        Version: GnuPG v1.4.3 (MingW32)
        Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

        iD8DBQFEicyxagV FX4UWr64RAhMXAJ 9zUQiKCbqNtfmep CYpysBlVeML5ACf UsVc
        /llIMf24SnZYOd3p DY2vBM8=
        =6eGA
        -----END PGP SIGNATURE-----

        Comment

        • Eric Sosman

          #5
          Re: Integer Promotion?



          Frederick Gotham wrote On 06/09/06 15:24,:[color=blue]
          > I set about trying to find a portable way to set the value of UCHAR_MAX. At
          > first, I thought the following would work:
          >
          > #define UCHAR_MAX ~( (unsigned char)0 )
          > [...][/color]

          You were right to suspect the integer promotions, and
          others have explained how they bollix things up for you.
          As for the portable expression, try

          #define MY_UCHAR_MAX ((unsigned char)-1)

          --
          Eric.Sosman@sun .com

          Comment

          • Frederick Gotham

            #6
            Re: Integer Promotion?

            Eric Sosman posted:
            [color=blue]
            >
            >
            > Frederick Gotham wrote On 06/09/06 15:24,:[color=green]
            >> I set about trying to find a portable way to set the value of
            >> UCHAR_MAX. At first, I thought the following would work:
            >>
            >> #define UCHAR_MAX ~( (unsigned char)0 )
            >> [...][/color]
            >
            > You were right to suspect the integer promotions, and
            > others have explained how they bollix things up for you.
            > As for the portable expression, try
            >
            > #define MY_UCHAR_MAX ((unsigned char)-1)[/color]


            I initially wrote code which used UCHAR_MAX, but then I made a C++
            template function out of it. Once I had made the template, I needed a
            universal way to get the maximum value for an unsigned integer type. At
            first, I had something like:

            (Don't worry, it's C code...

            typedef unsigned char AnyUnsignedInte gerType;

            void ArbitraryFunc()
            {
            AnyUnsignedInte gerType max_val = ~(AnyUnsignedIn tegerType)0;
            }


            But it didn't work.


            --

            Frederick Gotham

            Comment

            • Frederick Gotham

              #7
              Re: Integer Promotion?

              Ben Pfaff posted:

              [color=blue]
              > The operand of ~ is subject to the integer promotions, which
              > means that the `unsigned char' value 0 is converted to int (or,
              > possibly, to unsigned int) before the complement happens.[/color]


              Is there any sort of guide I can read which would show me when and why
              integer promotion happens?



              --

              Frederick Gotham

              Comment

              • pete

                #8
                Re: Integer Promotion?

                Frederick Gotham wrote:[color=blue]
                >
                > Eric Sosman posted:[/color]
                [color=blue][color=green]
                > > #define MY_UCHAR_MAX ((unsigned char)-1)[/color][/color]
                [color=blue]
                > void ArbitraryFunc()
                > {
                > AnyUnsignedInte gerType max_val = ~(AnyUnsignedIn tegerType)0;
                > }
                >
                > But it didn't work.[/color]

                As Eric Sosman implied, it's supposed to be:

                AnyUnsignedInte gerType max_val = (AnyUnsignedInt egerType)-1;

                That works for any and all unsigned integer types.

                --
                pete

                Comment

                • Eric Sosman

                  #9
                  Re: Integer Promotion?



                  Frederick Gotham wrote On 06/09/06 16:59,:[color=blue]
                  > Ben Pfaff posted:
                  >
                  >
                  >[color=green]
                  >>The operand of ~ is subject to the integer promotions, which
                  >>means that the `unsigned char' value 0 is converted to int (or,
                  >>possibly, to unsigned int) before the complement happens.[/color]
                  >
                  >
                  >
                  > Is there any sort of guide I can read which would show me when and why
                  > integer promotion happens?[/color]

                  Well, there's the Standard ...

                  Informally, when a "narrow" integer is used as an operand
                  or is passed to a function without a prototype or is passed as
                  one of the "..." arguments to a variable-argument function,
                  the value is first promoted to int or to unsigned int. But
                  let's not rush ahead: First, what's a "narrow" type?

                  Formally, the types subject to promotion are those whose
                  "rank" is less than that of int. Informally, these are the
                  types with "fewer bits" than int: char and short (on most
                  systems), bit-fields with small widths, and all of these in
                  both signed and unsigned flavors. If the compiler decides not
                  to use full-sized ints for some enum types, they are also
                  subject to promotion. In C99, the promotable list adds _Bool
                  and perhaps some implementation-defined narrow types that the
                  Standard doesn't enumerate.

                  All right, those are the types that get promoted. What
                  do they get promoted to? The rule is straightforward :

                  - If all the possible values of a "narrow" type can be
                  represented by an int, the type promotes to int.

                  - Otherwise, the type promotes to unsigned int.

                  The potentially tricky part is that stuff about ranges,
                  because the range of values a particular type can represent is
                  up to the implementation (subject to some requirements), and
                  the ranges vary from one implementation to another. Let's
                  work through a few examples.

                  First, an easy one: What happens to a short? The range
                  of short can be different on different implementations , but
                  we know it will never be wider than the range of the same
                  implementation' s int: Every short value is also a legitimate
                  int value. Therefore, short always promotes to int, on every
                  C implementation everywhere. That wasn't so bad, was it?

                  How about unsigned short? Now things get tougher. On
                  many systems an int has 32 bits and an unsigned short has 16.
                  On these systems, every unsigned short value is also an int
                  value, so unsigned short promotes to int. But what about a
                  system where int and short are both 16 bits wide? On such
                  systems INT_MAX will be 32767 but USHRT_MAX will go all the
                  way up to 65535, so there exist unsigned short values that
                  are too large for int. On these systems, unsigned short will
                  promote to unsigned int.

                  Similar issues arise with other narrow types: you usually
                  know that they are "narrow," but not what they'll promote to.
                  Even the lowly char promotes to int on some systems and to
                  unsigned int on others -- yes, Virginia, there are systems
                  where char and int have the same bit count, and if char is
                  unsigned (remember, the signedness of char is also at the
                  discretion of the implementation) CHAR_MAX will be equal to
                  UCHAR_MAX and both will be bigger than INT_MAX.

                  Why does C introduce all this confusion about promotion?
                  Hard to say for certain, but the confusion is probably an
                  attempt to make things simpler. ("Say, what?") Consider:
                  The underlying hardware probably doesn't have an instruction
                  that multiplies an unsigned short by a signed bit-field of
                  width eleven. Yet the language allows you as a programmer
                  to write such an expression, so what is the compiler to do
                  with it? C's answer is to promote the values to some flavor
                  of int, the machine's "natural" word size and the one most
                  likely to be supported best by the instruction set.

                  As a language, C is fairly close to the hardware. The
                  matter of promotion is one place where the hardware becomes
                  more visible to the programmer than it is elsewhere, and
                  sometimes more troublesome, too.

                  --
                  Eric.Sosman@sun .com

                  Comment

                  • Coos Haak

                    #10
                    Re: Integer Promotion?

                    Op Fri, 09 Jun 2006 21:55:01 GMT schreef pete:
                    [color=blue]
                    > Frederick Gotham wrote:[color=green]
                    >>
                    >> Eric Sosman posted:[/color]
                    >[color=green][color=darkred]
                    >>> #define MY_UCHAR_MAX ((unsigned char)-1)[/color][/color]
                    >[color=green]
                    >> void ArbitraryFunc()
                    >> {
                    >> AnyUnsignedInte gerType max_val = ~(AnyUnsignedIn tegerType)0;
                    >> }
                    >>
                    >> But it didn't work.[/color]
                    >
                    > As Eric Sosman implied, it's supposed to be:
                    >
                    > AnyUnsignedInte gerType max_val = (AnyUnsignedInt egerType)-1;
                    >
                    > That works for any and all unsigned integer types.[/color]

                    With one (albeit minor) provision that the machine uses two-complement
                    arithmetic ;-)
                    --
                    Coos

                    Comment

                    • Ben Pfaff

                      #11
                      Re: Integer Promotion?

                      Coos Haak <chforth@hccnet .nl> writes:
                      [color=blue]
                      > Op Fri, 09 Jun 2006 21:55:01 GMT schreef pete:[color=green]
                      >> As Eric Sosman implied, it's supposed to be:
                      >>
                      >> AnyUnsignedInte gerType max_val = (AnyUnsignedInt egerType)-1;
                      >>
                      >> That works for any and all unsigned integer types.[/color]
                      >
                      > With one (albeit minor) provision that the machine uses two-complement
                      > arithmetic ;-)[/color]

                      No, it has no such requirement. The C standard (C89 and C99)
                      specifies that a negative value is converted from a signed to an
                      unsigned type by adding Utype_MAX + 1.
                      --
                      "...what folly I commit, I dedicate to you."
                      --William Shakespeare, _Troilus and Cressida_

                      Comment

                      • Eric Sosman

                        #12
                        Re: Integer Promotion?



                        Coos Haak wrote On 06/09/06 18:10,:[color=blue]
                        > Op Fri, 09 Jun 2006 21:55:01 GMT schreef pete:
                        >
                        >[color=green]
                        >>Frederick Gotham wrote:
                        >>[color=darkred]
                        >>>Eric Sosman posted:[/color]
                        >>[color=darkred]
                        >>>> #define MY_UCHAR_MAX ((unsigned char)-1)[/color]
                        >>
                        >>
                        >>[color=darkred]
                        >>>void ArbitraryFunc()
                        >>>{
                        >>> AnyUnsignedInte gerType max_val = ~(AnyUnsignedIn tegerType)0;
                        >>>}
                        >>>
                        >>>But it didn't work.[/color]
                        >>
                        >>As Eric Sosman implied, it's supposed to be:
                        >>
                        >> AnyUnsignedInte gerType max_val = (AnyUnsignedInt egerType)-1;
                        >>
                        >>That works for any and all unsigned integer types.[/color]
                        >
                        >
                        > With one (albeit minor) provision that the machine uses two-complement
                        > arithmetic ;-)[/color]

                        I repeat: "For any and all unsigned integer types."
                        And I add: "... no matter what representation the machine
                        uses for negative signed integer types."

                        --
                        Eric.Sosman@sun .com

                        Comment

                        • Frank Silvermann

                          #13
                          Re: Integer Promotion?

                          Eric Sosman wrote:[color=blue]
                          >
                          > Frederick Gotham wrote On 06/09/06 16:59,:[color=green]
                          >> Ben Pfaff posted:
                          >>
                          >>
                          >>[color=darkred]
                          >>> The operand of ~ is subject to the integer promotions, which
                          >>> means that the `unsigned char' value 0 is converted to int (or,
                          >>> possibly, to unsigned int) before the complement happens.[/color]
                          >>
                          >>
                          >> Is there any sort of guide I can read which would show me when and why
                          >> integer promotion happens?[/color]
                          >
                          > Well, there's the Standard ...
                          >
                          > Informally, when a "narrow" integer is used as an operand
                          > or is passed to a function without a prototype or is passed as
                          > one of the "..." arguments to a variable-argument function,
                          > the value is first promoted to int or to unsigned int. But
                          > let's not rush ahead: First, what's a "narrow" type?
                          >
                          > Formally, the types subject to promotion are those whose
                          > "rank" is less than that of int. Informally, these are the
                          > types with "fewer bits" than int: char and short (on most
                          > systems), bit-fields with small widths, and all of these in
                          > both signed and unsigned flavors. If the compiler decides not
                          > to use full-sized ints for some enum types, they are also
                          > subject to promotion. In C99, the promotable list adds _Bool
                          > and perhaps some implementation-defined narrow types that the
                          > Standard doesn't enumerate.
                          >
                          > All right, those are the types that get promoted. What
                          > do they get promoted to? The rule is straightforward :
                          >
                          > - If all the possible values of a "narrow" type can be
                          > represented by an int, the type promotes to int.
                          >
                          > - Otherwise, the type promotes to unsigned int.
                          >
                          > The potentially tricky part is that stuff about ranges,
                          > because the range of values a particular type can represent is
                          > up to the implementation (subject to some requirements), and
                          > the ranges vary from one implementation to another. Let's
                          > work through a few examples.
                          >
                          > First, an easy one: What happens to a short? The range
                          > of short can be different on different implementations , but
                          > we know it will never be wider than the range of the same
                          > implementation' s int: Every short value is also a legitimate
                          > int value. Therefore, short always promotes to int, on every
                          > C implementation everywhere. That wasn't so bad, was it?
                          >
                          > How about unsigned short? Now things get tougher. On
                          > many systems an int has 32 bits and an unsigned short has 16.
                          > On these systems, every unsigned short value is also an int
                          > value, so unsigned short promotes to int. But what about a
                          > system where int and short are both 16 bits wide? On such
                          > systems INT_MAX will be 32767 but USHRT_MAX will go all the
                          > way up to 65535, so there exist unsigned short values that
                          > are too large for int. On these systems, unsigned short will
                          > promote to unsigned int.
                          >
                          > Similar issues arise with other narrow types: you usually
                          > know that they are "narrow," but not what they'll promote to.
                          > Even the lowly char promotes to int on some systems and to
                          > unsigned int on others -- yes, Virginia, there are systems
                          > where char and int have the same bit count, and if char is
                          > unsigned (remember, the signedness of char is also at the
                          > discretion of the implementation) CHAR_MAX will be equal to
                          > UCHAR_MAX and both will be bigger than INT_MAX.
                          >
                          > Why does C introduce all this confusion about promotion?
                          > Hard to say for certain, but the confusion is probably an
                          > attempt to make things simpler. ("Say, what?") Consider:
                          > The underlying hardware probably doesn't have an instruction
                          > that multiplies an unsigned short by a signed bit-field of
                          > width eleven. Yet the language allows you as a programmer
                          > to write such an expression, so what is the compiler to do
                          > with it? C's answer is to promote the values to some flavor
                          > of int, the machine's "natural" word size and the one most
                          > likely to be supported best by the instruction set.
                          >
                          > As a language, C is fairly close to the hardware. The
                          > matter of promotion is one place where the hardware becomes
                          > more visible to the programmer than it is elsewhere, and
                          > sometimes more troublesome, too.
                          >[/color]
                          #include <stdio.h>
                          #include <stdlib.h>


                          int main(void)
                          {
                          int i, a, b, d;
                          char c;
                          short e;

                          i = 0xFFFFFE3C;
                          c = i;
                          e = i;
                          a = sizeof(i);
                          b = sizeof(c);
                          d = sizeof(e);
                          printf("ints: %d while chars: %d and shorts: %d\n", a, b, d);
                          printf("c is %c\n", c);
                          printf("e is %hd\n", e);
                          return 0;
                          }
                          /* end source */
                          Am I getting closer to your point here, or closer to the confusion? The
                          char becomes '3C' and the short 'FE3C' frank

                          Comment

                          • Frank Silvermann

                            #14
                            Re: Integer Promotion?

                            Eric Sosman wrote:[color=blue]
                            >
                            > Frederick Gotham wrote On 06/09/06 16:59,:[color=green]
                            >> Ben Pfaff posted:
                            >>
                            >>
                            >>[color=darkred]
                            >>> The operand of ~ is subject to the integer promotions, which
                            >>> means that the `unsigned char' value 0 is converted to int (or,
                            >>> possibly, to unsigned int) before the complement happens.[/color]
                            >>
                            >>
                            >> Is there any sort of guide I can read which would show me when and why
                            >> integer promotion happens?[/color]
                            >
                            > Well, there's the Standard ...
                            >
                            > Informally, when a "narrow" integer is used as an operand
                            > or is passed to a function without a prototype or is passed as
                            > one of the "..." arguments to a variable-argument function,
                            > the value is first promoted to int or to unsigned int. But
                            > let's not rush ahead: First, what's a "narrow" type?
                            >
                            > Formally, the types subject to promotion are those whose
                            > "rank" is less than that of int. Informally, these are the
                            > types with "fewer bits" than int: char and short (on most
                            > systems), bit-fields with small widths, and all of these in
                            > both signed and unsigned flavors. If the compiler decides not
                            > to use full-sized ints for some enum types, they are also
                            > subject to promotion. In C99, the promotable list adds _Bool
                            > and perhaps some implementation-defined narrow types that the
                            > Standard doesn't enumerate.
                            >
                            > All right, those are the types that get promoted. What
                            > do they get promoted to? The rule is straightforward :
                            >
                            > - If all the possible values of a "narrow" type can be
                            > represented by an int, the type promotes to int.
                            >
                            > - Otherwise, the type promotes to unsigned int.
                            >
                            > The potentially tricky part is that stuff about ranges,
                            > because the range of values a particular type can represent is
                            > up to the implementation (subject to some requirements), and
                            > the ranges vary from one implementation to another. Let's
                            > work through a few examples.
                            >
                            > First, an easy one: What happens to a short? The range
                            > of short can be different on different implementations , but
                            > we know it will never be wider than the range of the same
                            > implementation' s int: Every short value is also a legitimate
                            > int value. Therefore, short always promotes to int, on every
                            > C implementation everywhere. That wasn't so bad, was it?
                            >
                            > How about unsigned short? Now things get tougher. On
                            > many systems an int has 32 bits and an unsigned short has 16.
                            > On these systems, every unsigned short value is also an int
                            > value, so unsigned short promotes to int. But what about a
                            > system where int and short are both 16 bits wide? On such
                            > systems INT_MAX will be 32767 but USHRT_MAX will go all the
                            > way up to 65535, so there exist unsigned short values that
                            > are too large for int. On these systems, unsigned short will
                            > promote to unsigned int.
                            >
                            > Similar issues arise with other narrow types: you usually
                            > know that they are "narrow," but not what they'll promote to.
                            > Even the lowly char promotes to int on some systems and to
                            > unsigned int on others -- yes, Virginia, there are systems
                            > where char and int have the same bit count, and if char is
                            > unsigned (remember, the signedness of char is also at the
                            > discretion of the implementation) CHAR_MAX will be equal to
                            > UCHAR_MAX and both will be bigger than INT_MAX.
                            >
                            > Why does C introduce all this confusion about promotion?
                            > Hard to say for certain, but the confusion is probably an
                            > attempt to make things simpler. ("Say, what?") Consider:
                            > The underlying hardware probably doesn't have an instruction
                            > that multiplies an unsigned short by a signed bit-field of
                            > width eleven. Yet the language allows you as a programmer
                            > to write such an expression, so what is the compiler to do
                            > with it? C's answer is to promote the values to some flavor
                            > of int, the machine's "natural" word size and the one most
                            > likely to be supported best by the instruction set.
                            >
                            > As a language, C is fairly close to the hardware. The
                            > matter of promotion is one place where the hardware becomes
                            > more visible to the programmer than it is elsewhere, and
                            > sometimes more troublesome, too.
                            >[/color]
                            #include <stdio.h>
                            #include <stdlib.h>


                            int main(void)
                            {
                            int i, a, b, d;
                            char c;
                            short e;

                            c = 'J';
                            e = c;
                            i = e;


                            a = sizeof(i);
                            b = sizeof(c);
                            d = sizeof(e);
                            printf("ints: %d while chars: %d and shorts: %d\n", a, b, d);
                            printf("c is %c\n", c);
                            printf("e is %hd\n", e);
                            printf("i is %d\n", i);
                            return 0;
                            }

                            Good grief. I'm not going to find an example of this trouble by the
                            integer demotion of the previous post. So I think I have signed versus
                            unsigned and at the fringes of the ranges. frank

                            Comment

                            • Frederick Gotham

                              #15
                              Re: Integer Promotion?

                              Eric Sosman posted:

                              [color=blue]
                              > - If all the possible values of a "narrow" type can be
                              > represented by an int, the type promotes to int.
                              >
                              > - Otherwise, the type promotes to unsigned int.[/color]


                              What if a signed short had 56 value bits and no padding bits, and a signed
                              int had 48 value bits and 8 padding bits? I believe this would satisfy:

                              sizeof(int) >= sizeof(short)

                              but at the same time, an "int" would have greater range than "short". In
                              such circumstances, you'd be promoting to a narrower type!


                              (Unless of course the Standard says that a signed int must have greater or
                              equal range than a signed short... ?)


                              --

                              Frederick Gotham

                              Comment

                              Working...