Arithmetic conversions and integer constants

S

Spiros Bousbouras

#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?
 
J

James Kuyper

Spiros said:
#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.
 
E

Eric Sosman

Spiros said:
#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.
 
S

Spiros Bousbouras

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 ;-)
 
S

Spiros Bousbouras

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.
 
J

James Kuyper

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.
 
K

Keith Thompson

James Kuyper said:
Spiros Bousbouras wrote:
...

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).
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top