views:

163

answers:

1

I'm trying to figure out if the C Standard (C90, though I'm working off Derek Jones' annotated C99 book) guarantees that I will not lose precision multiplying two unsigned 8-bit values and storing to a 16-bit result. An example statement is as follows:

unsigned char foo;
unsigned int foo_u16 = foo * 10;

Our Keil 8051 compiler (v7.50 at present) will generate a MUL AB instruction which stores the MSB in the B register and the LSB in the accumulator. If I cast foo to a unsigned int first:

unsigned int foo_u16 = (unsigned int)foo * 10;

then the compiler correctly decides I want a unsigned int there and generates an expensive call to a 16x16 bit integer multiply routine. I would like to argue beyond reasonable doubt that this defensive measure is not necessary. As I read the integer promotions described in 6.3.1.1, the effect of the first line shall be as if foo and 10 were promoted to unsigned int, the multiplication performed, and the result stored as unsigned int in foo_u16. If the compiler knows an instruction that does 8x8->16 bit multiplications without loss of precision, so much the better; but the precision is guaranteed. Am I reading this correctly?

Best regards, Craig Blome

+5  A: 

The promotion is guaranteed, but the promotion is made to signed int type if the range of unsigned char fits into the range of signed int. So (assuming it fits) from the language point of view your

unsigned int foo_u16 = foo * 10; 

is equivalent to

unsigned int foo_u16 = (signed) foo * 10; 

while what you apparently want is

unsigned int foo_u16 = (unsigned) foo * 10; 

The result of the multiplication can be different if it (the result) doesn't fit into the signed int range.

If your compiler interprets it differently, it could be a bug in the compiler (again, under the assumption that range of unsigned char fits into the range of signed int).

AndreyT
As long as `UCHAR_MAX` is less than 3277 (and the OP's question implies that `char` is 8 bit, so this is true), then the result will definitely fit into `signed int` and thus the result must be the same.
caf
Also, an alternate way to have the multiplication done on `unsigned int` operands would just be to specify the constant as `10U`.
caf
@caf: Yes, you are right. Even though the conceptual difference is there, the result shouldn't overflow.
AndreyT