2010-04-22 5 views
5

Estoy tratando de averiguar si el estándar C (C90, aunque estoy trabajando en el libro anotado C99 de Derek Jones) garantiza que no perderé precisión al multiplicar dos valores de 8 bits sin firmar y almacenarlos en 16 bits resultado. Un comunicado ejemplo es el siguiente:C: 8x8 -> 16 bit de precisión multiplicada garantizada por promociones enteras?

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

Nuestra Keil compilador 8051 (v7.50 en la actualidad) generará una instrucción MUL AB que almacena el MSB en el registro B y el LSB en el acumulador. Si yo echo foo a un unsigned int primero:

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

entonces el compilador decide correctamente que quiero un unsigned int allí y genera una llamada a una rutina costosa Multiplicar enteros bits de 16x16. Me gustaría argumentar más allá de toda duda razonable que esta medida defensiva no es necesaria. Al leer las promociones enteras descritas en 6.3.1.1, el efecto de la primera línea será como si foo y 10 fueran promovidos a unsigned int, la multiplicación realizada y el resultado almacenado como unsigned int en foo_u16. Si el compilador conoce una instrucción que hace multiplicaciones de 8x8-> 16 bits sin pérdida de precisión, tanto mejor; pero la precisión está garantizada. ¿Estoy leyendo esto correctamente?

Saludos, Craig Blome

Respuesta

5

La promoción está garantizada, pero la promoción se hace a signed int tipo si el rango de unsigned char encaja en la gama de signed int. Así que (suponiendo que cabe) desde el punto de vista del lenguaje de su

unsigned int foo_u16 = foo * 10; 

es equivalente a

unsigned int foo_u16 = (signed) foo * 10; 

, mientras que lo que aparentemente quiere es

unsigned int foo_u16 = (unsigned) foo * 10; 

El resultado de la multiplicación puede ser diferente si (el resultado) no encaja en el rango signed int.

Si su compilador lo interpreta de manera diferente, podría ser un error en el compilador (de nuevo, bajo el supuesto de que el rango de unsigned char se ajusta al rango de signed int).

+1

Siempre que 'UCHAR_MAX' sea menor que 3277 (y la pregunta de OP implica que' char' es 8 bit, entonces esto es cierto), entonces el resultado definitivamente encajará en 'signed int' y por lo tanto el resultado debe ser lo mismo. – caf

+0

Además, una forma alternativa de hacer la multiplicación en operandos 'unsigned int' sería simplemente especificar la constante como' 10U'. – caf

+0

@caf: Sí, tienes razón. Aunque la diferencia conceptual está ahí, el resultado no debe desbordarse. – AnT

Cuestiones relacionadas