Pregunta

unsigned char a, b;
b = something();
a = ~b;

Un analizador estático se quejó de truncamiento en la última línea, presumiblemente porque b se promueve a int antes de que se inviertan sus bits y el resultado será de tipo int.

Sólo me interesa el último byte del int promocionado, si b era 0x55, necesito a ser 0xAA.Mi pregunta es, ¿La especificación C dice algo sobre cómo ocurre el truncamiento?, ¿O es una implementación definida/indefinida?¿Está garantizado que a ¿Siempre se me asignará el valor que espero o podría salir mal en una plataforma conforme?

Por supuesto, transmitir el resultado antes de asignarlo silenciará el analizador estático, pero quiero saber si es seguro ignorar esta advertencia en primer lugar.

¿Fue útil?

Solución

El truncamiento ocurre como se describe en 6.3.1.3/2 del Estándar C99

...si el nuevo tipo no está firmado, el valor se convierte sumando o restando repetidamente uno más que el valor máximo que se puede representar en el nuevo tipo hasta que el valor esté en el rango del nuevo tipo.


Ejemplo para CHAR_BIT == 8, tamaño de (carácter sin firmar) == 1, tamaño de (int) == 4

Entonces, 0x55 se convierte a int, a 0x00000055, luego negado a 0xFFFFFFAA, y

      0xFFFFFFAA
    + 0x00000100 /* UCHAR_MAX + 1 */
    ------------
      0xFFFFFEAA

    ... repeat lots and lots of times ...

      0x000000AA

o, tan simple 0xAA, como era de esperar

Otros consejos

El estándar C especifica esto para los tipos sin firmar:

Un cálculo que involucra sin firmar Los operandos nunca pueden desbordarse, porque un resultado que no puede ser representado por el tipo de entero sin signo resultante es módulo reducido el número que es uno mayor que el valor más grande que puede ser representado por el resultado tipo.

En este caso, si su unsigned char es de 8 bits, significa que el resultado se reducirá módulo 256, lo que significa que si b era 0x55, a de hecho terminará como 0xAA.

Pero tenga en cuenta que si unsigned char es más ancho que 8 bits (lo cual es perfectamente legal), obtendrá un resultado diferente. Para asegurarse de que obtendrá de forma portátil 0xAA como resultado, puede utilizar:

a = ~b & 0xff;

(El bit a bit y debe optimizarse en plataformas donde unsigned char es de 8 bits).

Tenga en cuenta también que si usa un tipo firmado, el resultado está definido por la implementación.

Se comportará como usted desea.Es seguro emitir el valor.

Este ejemplo de código en particular es seguro.Pero hay razones para advertir contra el uso laxo del operador ~.

La razón detrás de esto es que ~ en variables enteras pequeñas es un error potencial en expresiones más complejas, debido a las promociones de enteros implícitas en C. Imagínese si tuviera una expresión como

a = ~b >> 4;

No cambiará a ceros como se esperaba.

Si su analizador estático está configurado para incluir MISRA-C, obtendrá, por ejemplo, esta advertencia para cada operador ~, porque MISRA impone el resultado de cualquier operación en tipos de enteros pequeños para que se tipifique explícitamente en el tipo esperado, unsigned charen este caso.

Tomemos el caso de la máquina Win32.
El número entero tiene 4 bytes y convertirlo en un carácter resultará exactamente como si se hubieran eliminado los 3 bytes restantes.

Al convertir un char en char, no importa a qué se promocione.
~b will add 3 bytes at the left change 0s to 1 and then remove... It does not affect your one right byte.

El mismo concepto será aplicable para diferentes arquitecturas (ya sea máquina de 16 o 64 bits)

Asumiendo que es little-endian

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top