Además de las respuestas ya publicadas y la comprensión de lo que hacen estos operadores, es igualmente importante entender qué tan peligrosos son los operadores de bitwise.
Estás utilizando literales enteros como 1
, un literal que es de tipo (con signo) int
. Los operadores firmados son peligrosos de usar junto con los operadores bitwise.
Muchos operadores como |
, ^
y ~
no se preocupan por el tipo de operandos, trabajan en el nivel binario sin formato. Pero los operadores de cambio pueden invocar varias formas desagradables de errores de comportamiento indefinido, en caso de cambiar un operando firmado. Por ejemplo, el código 1 << 31
invoca un comportamiento indefinido, ya que cambia los datos a los bits de signo. De manera similar, los cambios a la derecha de las variables firmadas tienen un comportamiento definido por la implementación si el operando es negativo.
Para empeorar las cosas, hay promociones enteras implícitas. Código como este también invoca un comportamiento indefinido:
unsigned char byte = 1;
byte = ~byte << 1;
Porque es lo mismo que 0xFFFF FFFE << 1
. Aquí puede pasar cualquier cosa, incluido un bloqueo del programa.
Del mismo modo, un código como este se comportará inesperadamente:
uint8_t mask = 0xF0;
uint8_t data = 0x01;
if(data > ~mask)
{
puts("0x01 is larger than 0x0F");
}
Lo que esto significa en la práctica es que cosas como las mencionadas leyes de De Morgan no se aplican de manera transparente al código C. Las promociones de tipo implícito y el comportamiento mal especificado pueden causar estragos.
La solución es evitar los tipos firmados en los sistemas integrados y escribir código lo más libre posible de promociones implícitas.
Más información: Reglas de promoción de tipo implícito .