promotion of integer types

S

shmartonak

I have the following program. Under linux I've compiled it with gcc and in DOS
I've compiled it with TURBOC 2.01. I get different outputs when I run it.

/* start of program */
#include <stdio.h>

int main()
{
unsigned char u1=200, u2=200;
unsigned long l1 = 0;
unsigned int i = 0;

printf("u1 = %u and u2 = %u\n", u1, u2 );
printf("l1 = %lu\n", l1 );

l1 = u1 * u2;
i = u1 * u2;
printf("After multiplying the unsigned int result is:\n");
printf("i = %u\n", i );
printf("and the unsigned long result is:\n");
printf("l1 = %lu\n", l1 );

return 0;
}
/* end of program */

******** results with gcc ******************
u1 = 200 and u2 = 200
l1 = 0
After multiplying the unsigned int result is:
i = 40000
and the unsigned long result is:
l1 = 40000


********** results with turboc ****************
u1 = 200 and u2 = 200
l1 = 0
After multiplying the unsigned int result is:
i = 40000
and the unsigned long result is:
l1 = 4294941760

***************************

Now my questions:

Where are the TURBOC results coming from? It looks like that an
intermediate result is being stored as a signed integer type before
being promoted to an unsigned long. Is this permitted or is this a bug
or what?

Second: Is the gcc result correct? If I'm reading the standard correctly the product
of two unsigned chars will never overflow but will be given modulo 256. Shouldn't
my product be given as 40000(mod 256) = 64 and then promoted to unsigned long?

BTW, thanks to all who reponded to my previous question about array indices.

Steve

--
 
M

Michael Mair

I have the following program. Under linux I've compiled it with gcc and in DOS
I've compiled it with TURBOC 2.01. I get different outputs when I run it.

/* start of program */
#include <stdio.h>

int main()
{
unsigned char u1=200, u2=200;
unsigned long l1 = 0;
unsigned int i = 0;

printf("u1 = %u and u2 = %u\n", u1, u2 );

I'd rather make this
printf("u1 = %u and u2 = %u\n", (unsigned int) u1,
(unsigned int) u2 );
printf("l1 = %lu\n", l1 );

l1 = u1 * u2;
(int) u1 * (int) u2 gives us an overflow for 16-Bit ints,
thus undefined behaviour, leading here to
40000-2^16 = -25536
(unsigned long)-25536 = 2^32-25536 = 4294941760
i = u1 * u2;

(int) u1 * (int) u2 gives us an overflow for 16-Bit ints,
thus undefined behaviour, leading here to
40000-2^16 = -25536
(unsigned int)-25536 = 2^16-25536 = 40000

gcc probably uses 32-Bit ints.


Cheers
Michael
printf("After multiplying the unsigned int result is:\n");
printf("i = %u\n", i );
printf("and the unsigned long result is:\n");
printf("l1 = %lu\n", l1 );

return 0;
}
/* end of program */
[snip: the above output for turboc, the expected for gcc]
 
A

Alex Fraser

I have the following program. Under linux I've compiled it with gcc and
in DOS I've compiled it with TURBOC 2.01. I get different outputs when I
run it.

/* start of program */
#include <stdio.h>

int main()
{
unsigned char u1=200, u2=200;
unsigned long l1 = 0;
unsigned int i = 0; [snip]
l1 = u1 * u2;
i = u1 * u2; [snip]
return 0;
}
/* end of program */

******** results with gcc ******************
u1 = 200 and u2 = 200
l1 = 0
After multiplying the unsigned int result is:
i = 40000
and the unsigned long result is:
l1 = 40000

********** results with turboc ****************
u1 = 200 and u2 = 200
l1 = 0
After multiplying the unsigned int result is:
i = 40000
and the unsigned long result is:
l1 = 4294941760

***************************

Now my questions:

Where are the TURBOC results coming from? It looks like that an
intermediate result is being stored as a signed integer type before
being promoted to an unsigned long. Is this permitted or is this a bug
or what?

The standard says that objects or expressions of rank less than int (such as
unsigned char) are converted to int (if int can represent all values of the
original type) or unsigned int (otherwise); this is known as integer
promotion.
Second: Is the gcc result correct? If I'm reading the standard correctly
the product of two unsigned chars will never overflow but will be given
modulo 256.

You're reading correctly, but missing a bit: values of type unsigned char
are never multiplied, they are promoted first by the rule above. But it is
true that the product of two values of unsigned type will be reduced
according to the range of values for that type.
Shouldn't my product be given as 40000(mod 256) = 64 and then promoted to
unsigned long?

No, the unsigned char values are promoted (probably to int in both cases),
then the promoted values are multiplied (causing overflow for the 16-bit int
apparently used by Turbo C). Finally, for GCC (the standard doesn't say what
Turbo C must do), the int result is converted (not promoted) to unsigned
long.

With educated guesses of the ranges of the types in both compilers, the GCC
result is correct, and the program invokes undefined behaviour with Turbo C,
due to the overflow.

Alex
 
S

shmartonak

The standard says that objects or expressions of rank less than int (such as
unsigned char) are converted to int (if int can represent all values of the
original type) or unsigned int (otherwise); this is known as integer
promotion.
...
You're reading correctly, but missing a bit: values of type unsigned char
are never multiplied, they are promoted first by the rule above.

That's what I needed to know. Thanks.

--
 

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

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top