Actualmente estoy escribiendo código para sistemas integrados (tanto en C como en C++) y al tratar de minimizar el uso de la memoria, noté que utilicé mucho código que se basa en promociones de enteros. Por ejemplo (que yo sepa, este código es idéntico en C y C++):
uint8_t brightness = 40; uint8_t maxval = 255; uint8_t localoutput = (brightness * maxval) / 100;Entonces, aunque el brillo * 255 es más grande que lo que se puede almacenar en un uint8_t, esto todavía produce el resultado correcto debido a las promociones de enteros, si estoy en lo correcto. El brillo es un porcentaje, por lo que nunca debe ser superior a 100 y, por lo tanto, la salida local nunca debe ser superior a 255. Mi pregunta es, entonces, si hay algún comportamiento inesperado (como el brillo * maxval es mayor que 255, por lo tanto, tiene un desbordamiento) o alguna diferencia significativa entre cómo se maneja esta sintaxis entre c ++ y c son el caso. Parece que solo genera la respuesta correcta, o sería más recomendable que las variables sean del tipo uint16_t, ya que los cálculos intermedios pueden ser superiores a 255, y simplemente dan por sentada la pérdida de memoria.
Su pregunta plantea un problema importante en la programación en C y en la programación en general: ¿el programa se comporta como se espera en todos los casos?
La expresión (brightness * maxval) / 100 calcula un valor intermedio de brightness * maxval que puede exceder el rango del tipo utilizado para calcularlo. En Python y algunos otros lenguajes, esto no es un problema porque los números enteros no tienen un rango restringido, pero en C, C++, java, javascript y muchos otros lenguajes, los tipos de números enteros tienen un número fijo de bits, por lo que la multiplicación puede exceder este rango. .
Es responsabilidad del programador asegurarse de que el rango de los operandos asegure que la multiplicación no se desborde. Esto requiere una buena comprensión de las reglas de conversión y promoción de enteros, que varían de un idioma a otro y son algo complicadas en C, especialmente con operandos que mezclan tipos con signo y sin signo.
En su caso particular, tanto el brightness como maxval tienen un tipo más pequeño que int , por lo que se promocionan a int con el mismo valor y la multiplicación produce un valor int . Si el brightness es un porcentaje en el rango de 0 a 100 , el resultado está en el rango de 0 a 25500 , que el Estándar C garantiza que está en el rango de tipo int , y dividir este número por 100 produce un valor en el rango de 0 a 100 , en el rango de int , y también en el rango del tipo de destino uint8_t , por lo que la operación está completamente definida.
Si este proceso debe documentarse en un comentario o verificarse con aserciones de depuración es una cuestión de reglas de codificación locales. Cambiar el orden de los operandos a maxval * brightness / 100 y posiblemente usar valores más explícitos y nombres de variables podría ayudar al lector:
uint8_t brightness100 = 40; uint8_t localoutput = 255 * brightness100 / 100;El problema es más general que una simple cuestión de promociones de enteros , todos esos cálculos deben analizarse para casos de esquina y rangos de valores. Las herramientas automatizadas pueden ayudar a realizar análisis de rango y los compiladores de optimización lo hacen para mejorar la generación de código, pero es un problema difícil.