Arithmetic conversions and integer constants

Discussion in 'C Programming' started by Spiros Bousbouras, Jan 13, 2009.

  1. #include <stdio.h>

    int main(void) {
    unsigned int foo = 2026363600u ;
    printf("off2 = %lu\n",
    838237499u * foo - 2137600414u);
    return 0;
    }

    Assuming C99 and that UINT_MAX == 1073741823 what will the above
    output? I'm thinking that foo will be assigned the value
    2026363600 % 1073741823 = 952621777 , the multiplication
    838237499u * foo will be done in unsigned so it will give
    ( 838237499 * 952621777 ) % 1073741823 = 504442367 , 2137600414u
    will be unsigned long because it's larger than UINT_MAX so
    504442367 will also be promoted to unsigned long and the
    subtraction will happen modulo ULONG_MAX so it will give the
    unsigned long result ULONG_MAX - (2137600414 - 504442367) which
    will be the final output. Have I got it right?

    A related question: what happens if an integer constant in the
    source code cannot fit in any integer type the implementation
    supports? Is it UB? Is the compiler obliged to give a warning
    because the constraint in p2 of 6.4.4 was violated?
    Spiros Bousbouras, Jan 13, 2009
    #1
    1. Advertising

  2. Spiros Bousbouras

    James Kuyper Guest

    Spiros Bousbouras wrote:
    > #include <stdio.h>
    >
    > int main(void) {
    > unsigned int foo = 2026363600u ;
    > printf("off2 = %lu\n",
    > 838237499u * foo - 2137600414u);
    > return 0;
    > }
    >
    > Assuming C99 and that UINT_MAX == 1073741823 what will the above
    > output? I'm thinking that foo will be assigned the value
    > 2026363600 % 1073741823 = 952621777 , the multiplication
    > 838237499u * foo will be done in unsigned so it will give
    > ( 838237499 * 952621777 ) % 1073741823 = 504442367 , 2137600414u


    That should be % 1073741824.

    > will be unsigned long because it's larger than UINT_MAX so
    > 504442367 will also be promoted to unsigned long and the


    Actually, that depends upon whether or not 2137600414u > ULONG_MAX. If
    it is, then it will be "unsigned long long", not "unsigned long", and
    the format code you gave printf() will be incorrect.

    > subtraction will happen modulo ULONG_MAX so it will give the


    That should be ULONG_MAX+1 (or ULLONG_MAX).

    > unsigned long result ULONG_MAX - (2137600414 - 504442367) which
    > will be the final output. Have I got it right?



    > A related question: what happens if an integer constant in the
    > source code cannot fit in any integer type the implementation
    > supports? Is it UB? Is the compiler obliged to give a warning
    > because the constraint in p2 of 6.4.4 was violated?


    6.4.4.1p5 gives the normal method of determining the type of an integer
    constant, but it fails in this case. 6.4.4.1p6 covers that failure: "If
    an integer constant cannot be represented by any type in its list and
    has no extended integer type, then the integer constant has no type."
    Having no type violates the constraint in 6.4.4p2, mandating a
    diagnostic. Use of such an integer constant in any context where it's
    type is relevant has implicitly undefined behavior. Off hand, I can't
    think of any contexts in which the type is not relevant, but I wouldn't
    be surprised to learn that there was one I had missed.
    James Kuyper, Jan 13, 2009
    #2
    1. Advertising

  3. Spiros Bousbouras

    Eric Sosman Guest

    Spiros Bousbouras wrote:
    > #include <stdio.h>
    >
    > int main(void) {
    > unsigned int foo = 2026363600u ;
    > printf("off2 = %lu\n",
    > 838237499u * foo - 2137600414u);
    > return 0;
    > }
    >
    > Assuming C99 and that UINT_MAX == 1073741823 what will the above
    > output? I'm thinking that foo will be assigned the value
    > 2026363600 % 1073741823 = 952621777 , the multiplication
    > 838237499u * foo will be done in unsigned so it will give
    > ( 838237499 * 952621777 ) % 1073741823 = 504442367 , 2137600414u
    > will be unsigned long because it's larger than UINT_MAX so
    > 504442367 will also be promoted to unsigned long and the
    > subtraction will happen modulo ULONG_MAX so it will give the
    > unsigned long result ULONG_MAX - (2137600414 - 504442367) which
    > will be the final output. Have I got it right?


    No. Let's take it step by step:

    unsigned int foo = 2026363600u ;

    By assumption, 2026363600 > UINT_MAX so the initializer's type
    is unsigned long. This is converted to unsigned int by reducing
    modulo UINT_MAX+1 (not UINT_MAX), yielding foo == 952621776u.

    838237499u * foo

    838237499 < UINT_MAX, so both operands are of type unsigned int.
    The product 838237499u * 952621776u -> 798523295007178224 is too
    large for an unsigned int and is reduced modulo UINT_MAX+1 (not
    UINT_MAX), yielding 1070005744u.

    1070005744u - 2137600414u

    2137600414 > UINT_MAX, so the second operand is of type unsigned
    long (not unsigned long long, because 2137600414 < ULONG_MAX).
    The first operand is promoted to unsigned long, retaining its value,
    then 1070005744ul - 2137600414ul -> -1067594670. This is too small
    for an unsigned long, so it is "reduced" modulo ULONG_MAX+1 (not
    ULONG_MAX). ULONG_MAX isn't revealed, but it's >= 4294967295
    and is one less than a power of two, so the result is one of
    3227372625ul, 5362561966ul, ...

    > A related question: what happens if an integer constant in the
    > source code cannot fit in any integer type the implementation
    > supports? Is it UB? Is the compiler obliged to give a warning
    > because the constraint in p2 of 6.4.4 was violated?


    It's a constraint violation, so a diagnostic is required.

    --
    Eric Sosman
    lid
    Eric Sosman, Jan 13, 2009
    #3
  4. On 13 Jan, 14:14, Eric Sosman <> wrote:
    > Spiros Bousbouras wrote:
    > > #include <stdio.h>

    >
    > > int main(void) {
    > > unsigned int foo = 2026363600u ;
    > > printf("off2 = %lu\n",
    > > 838237499u * foo - 2137600414u);
    > > return 0;
    > > }

    >
    > > Assuming C99 and that UINT_MAX == 1073741823 what will the above
    > > output? I'm thinking that foo will be assigned the value
    > > 2026363600 % 1073741823 = 952621777 , the multiplication
    > > 838237499u * foo will be done in unsigned so it will give
    > > ( 838237499 * 952621777 ) % 1073741823 = 504442367 , 2137600414u
    > > will be unsigned long because it's larger than UINT_MAX so
    > > 504442367 will also be promoted to unsigned long and the
    > > subtraction will happen modulo ULONG_MAX so it will give the
    > > unsigned long result ULONG_MAX - (2137600414 - 504442367) which
    > > will be the final output. Have I got it right?

    >
    > No. Let's take it step by step:
    >
    > unsigned int foo = 2026363600u ;
    >
    > By assumption, 2026363600 > UINT_MAX so the initializer's type
    > is unsigned long. This is converted to unsigned int by reducing
    > modulo UINT_MAX+1 (not UINT_MAX),


    Dooh , I fell victim to a bug in my wetware ;-)
    Spiros Bousbouras, Jan 14, 2009
    #4
  5. On 13 Jan, 13:03, James Kuyper <> wrote:
    > Spiros Bousbouras wrote:
    >
    > > A related question: what happens if an integer constant in the
    > > source code cannot fit in any integer type the implementation
    > > supports? Is it UB? Is the compiler obliged to give a warning
    > > because the constraint in p2 of 6.4.4 was violated?

    >
    > 6.4.4.1p5 gives the normal method of determining the type of an integer
    > constant, but it fails in this case. 6.4.4.1p6 covers that failure: "If
    > an integer constant cannot be represented by any type in its list and
    > has no extended integer type, then the integer constant has no type."


    This is quite clear. I was looking at the printed standard where
    this sentence doesn't exist but it has been added in n1256.pdf

    > Having no type violates the constraint in 6.4.4p2, mandating a
    > diagnostic.


    Another point where n1256.pdf is more complete than the official
    document.

    Standard:
    The value of a constant shall be in the range of
    representable values for its type.

    n1256.pdf:
    Each constant shall have a type and the value of
    a constant shall be in the range of representable
    values for its type.
    Spiros Bousbouras, Jan 14, 2009
    #5
  6. Spiros Bousbouras

    James Kuyper Guest

    Spiros Bousbouras wrote:
    ....
    > Another point where n1256.pdf is more complete than the official
    > document.
    >
    > Standard:
    > The value of a constant shall be in the range of
    > representable values for its type.
    >
    > n1256.pdf:
    > Each constant shall have a type and the value of
    > a constant shall be in the range of representable
    > values for its type.


    Keep in mind that n1256.pdf is the currently approved standard with all
    currently approved revisions applied, so presumably you can find that
    change specified in one of the three Technical Corrigenda. While the
    base document and the revisions have each been officially approved, my
    understanding is that the revised document has not been, and will not be.
    James Kuyper, Jan 14, 2009
    #6
  7. James Kuyper <> writes:
    > Spiros Bousbouras wrote:
    > ...
    >> Another point where n1256.pdf is more complete than the official
    >> document.
    >> Standard:
    >> The value of a constant shall be in the range of
    >> representable values for its type.
    >> n1256.pdf:
    >> Each constant shall have a type and the value of
    >> a constant shall be in the range of representable
    >> values for its type.

    >
    > Keep in mind that n1256.pdf is the currently approved standard with
    > all currently approved revisions applied, so presumably you can find
    > that change specified in one of the three Technical Corrigenda. While
    > the base document and the revisions have each been officially
    > approved, my understanding is that the revised document has not been,
    > and will not be.


    n1256 also contains a few minor editorial fixes that aren't in C99 or
    any of the three TCs. For example, IIRC, it uses the words "return"
    and "yield" more consistently (functions *return* values, expressions
    *yield" values).

    The above example is not a minor editorial fix, and I presume it's in
    one of the TCs (I haven't checked).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jan 14, 2009
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?ISO-8859-1?Q?Christian_Brechb=FChler?=

    Arithmetic conversions/promotion and templates

    =?ISO-8859-1?Q?Christian_Brechb=FChler?=, Oct 19, 2003, in forum: C++
    Replies:
    3
    Views:
    418
    =?ISO-8859-1?Q?Christian_Brechb=FChler?=
    Oct 20, 2003
  2. Niels Dekker (no reply address)

    Usual arithmetic conversions + integral promotion for short?

    Niels Dekker (no reply address), May 19, 2004, in forum: C++
    Replies:
    10
    Views:
    1,919
    Niels Dekker (no reply address)
    May 22, 2004
  3. Dan Stromberg
    Replies:
    2
    Views:
    478
    Michael Spencer
    Jan 22, 2005
  4. joshc
    Replies:
    5
    Views:
    553
    Keith Thompson
    Mar 31, 2005
  5. Replies:
    10
    Views:
    706
    Jasen Betts
    Aug 5, 2005
Loading...

Share This Page