En los títulos y los textos vais a encontrar unas cuantas citaciones cinematográficas (y si, soy un cinéfilo). Si no os interesan podéis fingir no verlas, ya que no son fundamentales para la comprensión de los post...

Este blog es la versión en Español de mi blog en Italiano L'arte della programmazione in C. Espero que mis traducciones sean comprensibles...

miércoles, 13 de noviembre de 2013

¡Bitwise operations!
cómo usar los operadores Bitwise en C - pt.1

Aunque éste es un blog de estilo (por si alguien todavía no se había dado cuenta...), he decidido, durante un tiempo, continuar con mi trabajo meritorio (¡que modestia!) de actualizar algunos temas que me imagino que todo el mundo ha leído y/o estudiado (tal vez en el K&R), y luego han rápidamente olvidado, porque seamos sinceros, el C contiene partes bastantes especializadas y de uso marginal, que en algunos entornos de programación no se utilizan nunca (¡nunca nunca!).

Repetimos el juego del post anterior: que levante la mano quien ha escrito recientemente código que utiliza las operaciones bit a bit. O bien, levante la mano, sin antes ir a volver a leer un manual de C, aquellos de vosotros que saben cómo usar y/o describir perfectamente las operaciones bit a bit. Uhmm ... Veo pocas manos levantadas. El hecho es que las bitwise opeartions son una de las partes del C menos conocida, de uso dudoso y poco frecuente, en definitiva, una de las partes que, por falta de práctica, se olvida (y he usado exactamente las mismas palabras del post anterior: soy ecologista, cuando puedo reciclo).

En comparación con las union, por otra parte, hay que decir que sobre las operaciones bit a bit el fantástico K&R no es particularmente claro y detallado, y las trata (como son) como un tema secundario, y no te involucra con decenas de ejemplos entretenidos que te ayudan en memorizar perfectamente el argumento, de hecho, que yo recuerde de la última vez que lo leí, hay solo un par de páginas que te se escapaban de las manos y que ya has olvidado cuando pasas al siguiente capítulo. Bueno, la biblia K&R (que considero sagrada) tiene algunos puntos no tan atractivos.

Refrescamos: los operadores de bitwise (que operan en los bits individuales) son:
"&"  AND
"|"  OR
"^"  XOR
"~"  NOT (complemento a 1)
"<<" SHIFT hacia la izquierda
">>" SHIFT hacia la derecha
  
NOTA: 
- el NOT es un operador unario: funciona con un solo argumento indicado 
  a la derecha. 
- los operadores de shift son operadores unarios: operan con un solo 
  argumento indicado a la izquierda.  
Ahora bien, sin entrar en discursos aburridos, nos dirigimos a una pequeña tabla y a algunos ejemplos sencillos.

Aquí está la tabla:
"& ":  el resultado es 1 si los dos operandos son 1. En caso contrario 0. 
"|" :  el resultado es 0 si los dos operandos son 0. En caso contrario 1. 
"^ ":  el resultado es 1 si los dos operandos son diferentes. En caso contrario 0. 
"~ ":  el resultado es 1 si el operando es 0. En caso contrario 0. 
"<<n": el resultado es el operando con todos los bits desplazados a la 
       izquierda por n posiciones. 
">>n": el resultado es el operando con todos los bits desplazados a la 
       derecha por n posiciones.
Y aquí están los simples ejemplos prácticos:
AND
int a = 74;       // 0 1 0 0 1 0 1 0
int b = 174;      // 1 0 1 0 1 1 1 0
int c = a & b;    // 0 0 0 0 1 0 1 0 resultado c=10

OR
int a = 74;       // 0 1 0 0 1 0 1 0
int b = 174;      // 1 0 1 0 1 1 1 0
int c = a | b;    // 1 1 1 0 1 1 1 0 resultado c=238

XOR
int a = 74;       // 0 1 0 0 1 0 1 0
int b = 174;      // 1 0 1 0 1 1 1 0
int c = a & b;    // 1 1 1 0 0 1 0 0 resultado c=228

NOT
int a = 74;       // 0 1 0 0 1 0 1 0
int b = ~b;       // 1 0 1 1 0 1 0 1 resultado c=181

SHIFT hacia la izquierda
int a = 74;       // 0 1 0 0 1 0 1 0
int b = a<<2;     // 0 0 1 0 1 0 0 0 resultado c=296

SHIFT hacia la derecha
int a = 74;       // 0 1 0 0 1 0 1 0
int b = a>>2;     // 0 0 0 1 0 0 1 0 resultado c=18
Tener en cuenta que en las operaciones de shift los bits nuevos que entran por la derecha (en el shift hacia la izquierda) valen 0, y los bit nuevos que entran por la izquierda (en el shift hacia la derecha) valen 0.

Tener en cuenta también que el shift hacia la derecha es equivalente a una división por múltiplos de 2 (>>1 es una división por 2, >>2 es una división por 4, etc.) , Mientras que el shift hacia la izquierda es equivalente a una multiplicación por múltiplos de 2 (<<1 es una multiplicación por 2, <<2 es una multiplicación por 4, etc.). Estas operaciones de multiplicación y división son muy rápidas, y se puede tener la tentación de utilizarlas para acelerar el código: bueno, antes de hacerlo, leer de nuevo (o leer) esto.

Y me gustaría añadir una advertencia: en función del tamaño del tipo del operando, y la presencia o ausencia del bit de signo, las multiplicaciones y divisiones con shift pueden dar resultados inesperados. Hablaremos de esto en el próxima episodio, donde vamos a hacer unos cuantos ejemplos prácticos de código que utiliza las bitwise operations (y no contengáis la respiración, mientras tanto...).

Hasta el próximo post.