18 Operadores IV: Más operadores

Alguien dijo una vez que C prácticamente tiene un operador para cada instrucción de ensamblador. De hecho C y mucho más C++ tiene una enorme riqueza de operadores, éste es el tercer capítulo dedicado a operadores, y aún nos quedan más operadores por ver.

Operadores de bits

Estos operadores trabajan con las expresiones que manejan manipulándolas a nivel de bit, y sólo se pueden aplicar a expresiones enteras. Existen seis operadores de bits, cinco binarios y uno unitario: "&", "|", "^", "~", ">>" y "<<".

Sintaxis:

<expresión> & <expresión>
<expresión> ^ <expresión>
<expresión> | <expresión>
~<expresión>
<expresión> << <expresión>
<expresión> >> <expresión>

El operador "&" corresponde a la operación lógica "AND", o en álgebra de Boole al operador "·", compara los bits uno a uno, si ambos son "1" el resultado es "1", en caso contrario "0".

El operador "^" corresponde a la operación lógica "OR exclusivo", compara los bits uno a uno, si ambos son "1" o ambos son "0", el resultado es "0", en caso contrario "1".

El operador "|" corresponde a la operación lógica "OR", o en álgebra de Boole al operador "+", compara los bits uno a uno, si uno de ellos es "1" el resultado es "1", en caso contrario "0".

El operador "~", (se obtiene con la combinación de teclas ALT+126, manteniendo pulsada la tecla "ALT", se pulsan las teclas "1", "2" y "6" del teclado numérico, o bien con la combinación de teclas AltGr+4 seguido de un espacio), corresponde a la operación lógica "NOT", se trata de un operador unitario que invierte el valor de cada bit, si es "1" da como resultado un "0", y si es "0", un "1".

El operador "<<" realiza un desplazamiento de bits a la izquierda del valor de la izquierda, introduciendo "0" por la derecha, tantas veces como indique el segundo operador; equivale a multiplicar por 2 tantas veces como indique el segundo operando.

El operador ">>" realiza un desplazamiento de bits a la derecha del valor de la izquierda, introduciendo "0" por la izquierda, tantas veces como indique el segundo operador; equivale a dividir por 2 tantas veces como indique el segundo operando.

Tablas de verdad:

Operador 1 Operador 2 AND OR exclusivo OR inclusivo NOT
E1
E2
E1 & E2
E1 ^ E2
E1 | E2
~E1
0
0
0
0
0
1
1
0
0
1
1
0
0
1
0
1
1
1
1
1
1
0
1
0

Ya hemos visto que los operadores '~', '&', '<<' y '>>' tienen otras aplicaciones diferentes, su funcionamiento es contextual, es decir, se decide después del análisis de los operandos. En C++ se conoce esta reutilización de operadores como sobrecarga de operadores o simplemente sobrecarga, más adelante introduciremos un capítulo dedicado a este tema.

Ejemplos

Espero que estés familiarizado con la numeración hexadecimal, ya que es vital para interpretar las operaciones con bits.

De todos modos, no es demasiado complicado. Existe una correspondencia directa entre los dígitos hexadecimales y combinaciones de cuatro dígitos binarios, veamos una tabla:

Hexadecimal Binario Hexadecimal Binario
0
0000
8
1000
1
0001
9
1001
2
0010
A
1010
3
0011
B
1011
4
0100
C
1100
5
0101
D
1101
6
0110
E
1110
7
0111
F
1111
int a, b, c;

a = 0xd3; // = 11010011
b = 0xf5; // = 11110101
c = 0x1e; // = 00011110

d = a | b; // 11010011 | 11110101 = 11110111 -> 0xf7
d = b & c; // 11110101 & 00011110 = 00010100 -> 0x14
d = a ^ c; // 11010011 ^ 00011110 = 11001101 -> 0xcd
d = ~c;    // ~00011110 = 11100001 -> 0xe1
d = c << 3 // 00011110 << 3 = 11110000 ->; 0xf0
d = a >> 4 // 11010011 >> 4 = 00001101 ->; 0x0d

Operador condicional

El operador "?:", se trata de un operador ternario.

Sintaxis:

<expresión lógica> ? <expresión> : <expresión>

En la expresión E1 ? E2 : E3, primero se evalúa la expresión E1, si el valor es verdadero (true), se evaluará la expresión E2 y E3 será ignorada, si es falso (false), se evaluará E3 y E2 será ignorada.

Hay ciertas limitaciones en cuanto al tipo de los argumentos.

  • E1 debe ser una expresión lógica.

E2 y E3 han de seguir una de las siguientes reglas:

  • Ambas de tipo aritmético.
  • Ambas de estructuras o uniones compatibles.
  • Ambas de tipo void.

Hay más reglas, pero las veremos más adelante, ya que aún no hemos visto nada sobre los conocimientos implicados.

Como ejemplo veremos cómo se puede definir la macro "max":

#define max(a,b) (((a) > (b)) ? (a) : (b))

De este ejemplo sólo nos interesa la parte de la derecha. La interpretación es: si "a" es mayor que "b", se debe evaluar "a", en caso contrario evaluar "b".

Otros ejemplos prácticos:

Cuando el número a mostrar sea uno, el texto será un singular "elemento", si es otro número, será el plural "elementos".

    cout << "Tenemos " << n << ((n!=1) ? "elementos" : "elemento") << endl;

Mostrar los varlores de un array separados con comas, en seis columnas:

    int v[] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24 };
    int N = 24;
    for(int i = 0; i < N; i++)
        cout << v[i] << ((i%6==5 || i==N-1) ? "\n" : ",");