14 Operadores III: Precedencia

Normalmente, las expresiones con operadores se evalúan de izquierda a derecha, aunque no todos, ciertos operadores que se evalúan y se asocian de derecha a izquierda. Además no todos los operadores tienen la misma prioridad, algunos se evalúan antes que otros, de hecho, existe un orden muy concreto en los operadores en la evaluación de expresiones. Esta propiedad de los operadores se conoce como precedencia o prioridad.

Veremos ahora las prioridades de todos los operadores incluidos los que aún conocemos. Considera esta tabla como una referencia, no es necesario aprenderla de memoria, en caso de duda siempre se puede consultar, incluso puede que cambie ligeramente según el compilador, y en último caso veremos sistemas para eludir la precedencia.

Operadores Asociatividad
() [] -> :: . Izquierda a derecha
Operadores unitarios: ! ~ + - ++ -- & (dirección de) * (puntero a) sizeof new delete Derecha a izquierda
.* ->* Izquierda a derecha
* (multiplicación) / % Izquierda a derecha
+ - (operadores binarios) Izquierda a derecha
<< >> Izquierda a derecha
< <= > >= Izquierda a derecha
== != Izquierda a derecha
& (bitwise AND) Izquierda a derecha
^ (bitwise XOR) Izquierda a derecha
| (bitwise OR) Izquierda a derecha
&& Izquierda a derecha
|| Izquierda a derecha
?: Derecha a izquierda
= *= /= %= += -= &= ^= |= <<= >>= Derecha a izquierda
, Izquierda a derecha

La tabla muestra las precedencias de los operadores en orden decreciente, los de mayor precedencia en la primera fila. Dentro de la misma fila, la prioridad se decide por el orden de asociatividad.

La asociatividad nos dice en que orden se aplican los operadores en expresiones complejas, por ejemplo:

int a, b, c, d, e; 
b = c = d = e = 10;

El operador de asignación "=" se asocia de derecha a izquierda, es decir, primero se aplica "e = 10", después "d = e", etc. O sea, a todas las variables se les asigna el mismo valor: 10.

a = b * c + d * e;

El operador * tiene mayor precedencia que + e =, por lo tanto se aplica antes, después se aplica el operador +, y por último el =. El resultado final será asignar a "a" el valor 200.

int m[10] = {10,20,30,40,50,60,70,80,90,100}, *f; 
f = &m[5]; 
++*f; 
cout << *f << endl;

La salida de este ejemplo será, 61, los operadores unitarios tienen todos la misma precedencia, y se asocian de derecha a izquierda. Primero se aplica el *, y después el incremento al contenido de f.

f = &m[5]; 
*f--;
cout << *f << endl;

La salida de este ejemplo será, 50. Primero se aplica el decremento al puntero, y después el *.

a = b * (c + d) * e;

Ahora el operador de mayor peso es (), ya que los paréntesis están en el grupo de mayor precedencia. Todo lo que hay entre los paréntesis se evalúa antes que cualquier otra cosa. Primero se evalúa la suma, y después las multiplicaciones. El resultado será asignar a la variable "a" el valor 2000.

Este es el sistema para eludir las precedencias por defecto, si queremos evaluar antes una suma que un producto, debemos usar paréntesis.

Comentarios de los usuarios (4)

B. Amauri
2013-11-25 21:03:11

¡Buenos días!

Deseo aclarar un error en la explicación que dieron más arriba sobre la precedencia, pues éste fue causa de que tuvierea problemas para entender el tema.

"

f = &m[5]; 
*f--;
cout << *f << endl;
La salida de este ejemplo será, 50. Primero se aplica el decremento al puntero, y después el *."

La salida es, en efecto, 50, pero no se debe a que el decremento se aplique primero y después la indirección.

El decremento es un "pos-decremento", por lo tanto se evalúa la primera expresión, sin ninguna salida visible, y después se realiza el decremento al puntero. Entonces, cuando imprime la indirección de f, éste ya apunta al elemento anterior.

Steven R. Davidson
2013-11-25 22:23:39

Hola B. Amauri,

En parte, tienes razón. En la segunda sentencia, el operador de posdecremento se evalúa primero, y luego el operador de indirección (acceso). Esto significa que, desde el punto de vista del lenguaje, el orden de evaluación es:

(*(f--))

que viene a ser equivalente a:

1. f--

2. *f

Ahora bien, el operador de posdecremento no termina su evaluación en el paso #1, sino al finalizar el paso #2. Los operadores de posdecremento y posincremento son un poco raros en ese sentido. Su evaluación no conlleva a realizar su tarea en el momento de su evaluación, sino que se aplica su tarea póstumamente.

Dicho lo anterior, lo que sí podemos hacer es cambiar el término "aplicar" en el capítulo a "evaluar", dejando el término "aplicar" para referirnos al momento de realizar la tarea del operador. En general, se intercambian ambos términos, pero en el caso de C/C++ y particularmente en los casos de los operadores póstumos, tenemos que separar ambos términos.

Gracias por la observación.

Steven

Carlos
2016-08-21 20:40:13

Tengo una duda, ¿por qué pones un asterisco (*) después del operador . y del operador ->? Se puede ver en la fila 3

Steven R. Davidson
2016-08-22 02:50:54

Hola Carlos,

Se trata de dos operadores (propios de C++) diferentes a los conocidos de C/C++.

Hablamos de estos operadores en el capítulo 41 que trata el tema de punteros a miembros. Puedes dirigirte a: http://c.conclase.net/curso/index.php?cap=041#inicio

Espero haber aclarado la duda.

Steven