Velocity Reviews > Arithmetic conversions and integer constants

# Arithmetic conversions and integer constants

Spiros Bousbouras
Guest
Posts: n/a

 01-13-2009
#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?

James Kuyper
Guest
Posts: n/a

 01-13-2009
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.

Eric Sosman
Guest
Posts: n/a

 01-13-2009
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
http://www.velocityreviews.com/forums/(E-Mail Removed)lid

Spiros Bousbouras
Guest
Posts: n/a

 01-14-2009
On 13 Jan, 14:14, Eric Sosman <(E-Mail Removed)> 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
Guest
Posts: n/a

 01-14-2009
On 13 Jan, 13:03, James Kuyper <(E-Mail Removed)> 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.

James Kuyper
Guest
Posts: n/a

 01-14-2009
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.

Keith Thompson
Guest
Posts: n/a

 01-14-2009
James Kuyper <(E-Mail Removed)> 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) (E-Mail Removed) <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"