Tengo el siguiente código:
unsigned char x = 255; printf("%x\n", x); // ff unsigned char tmp = x << 7; unsigned char y = tmp >> 7; printf("%x\n", y); // 1 unsigned char z = (x << 7) >> 7; printf("%x\n", z); // ff Habría esperado que y y z fueran iguales. Pero difieren dependiendo de si se utiliza una variable intermediaria. Sería interesante saber por qué es así.
El operador de desplazamiento no está definido para los char de caracteres. El valor de cualquier operando char se convierte a int y el resultado de la expresión se convierte al tipo char . Entonces, cuando coloca los operadores de desplazamiento a la izquierda y a la derecha en la misma expresión, el cálculo se realizará como tipo int (sin perder ningún bit), y el resultado se convertirá en char .
Los valores 'intermedios' en su último caso son enteros (completos), por lo que los bits que se desplazan 'fuera de rango' del tipo de unsigned char se conservan y, por lo tanto, aún se establecen cuando el resultado se convierte de nuevo en un solo byte.
De este Proyecto de Norma C11 :
6.5.7 Operadores de desplazamiento bit a bit
...
3 Las promociones de enteros se realizan en cada uno de los operandos. El tipo del resultado es el del operando izquierdo ascendido...
Sin embargo, en su primer caso, unsigned char tmp = x << 7; , el tmp pierde los seis bits 'altos' cuando el entero 'completo' resultante se convierte (es decir, se trunca ) de nuevo en un solo byte, dando un valor de 0x80 ; cuando esto se desplaza a la derecha en unsigned char y = tmp >> 7; , el resultado es (como se esperaba) 0x01 .