Una operación lógica con una alta prioridad de ejecución. Orden de prioridad y ejecución

Anotación: Se consideran la sintaxis y la semántica de la construcción de expresiones en el lenguaje C#. Se consideran todas las operaciones lingüísticas posibles y sus prioridades. Al considerar operaciones lógicas, se analiza el trabajo con escalas. Se consideran el operador lambda y la expresión lambda. Se presta mucha atención a las conversiones de tipos de datos al evaluar expresiones. Se discuten cuestiones relacionadas con la evaluación eficiente de expresiones. Se proponen problemas sobre este tema.

Puedes descargar el proyecto de esta conferencia. .

Expresiones

Expresiones se construyen a partir de operandos (constantes, variables, funciones) unidos por signos de operación y paréntesis. Cuando se evalúa una expresión, se determina su valor y tipo. Estas características de una expresión están determinadas únicamente por los valores y tipos de operandos incluidos en la expresión y las reglas para evaluar la expresión. Las reglas son:

  • una prioridad operaciones,
  • para operaciones de la misma prioridad procedimiento de solicitud- de izquierda a derecha o de derecha a izquierda;
  • convertir tipos de operandos y elegir implementaciones para operadores sobrecargados;
  • tipo y valor del resultado de realizar una operación en valores dados operandos de un determinado tipo.

Prioridad y orden de operaciones.

La mayoría de las operaciones en el lenguaje C#, su prioridad y orden, se heredan del lenguaje C++. Sin embargo, también existen diferencias: por ejemplo, no existe una operación " , " que le permita evaluar una lista de expresiones; Se agregaron operaciones marcadas y no marcadas aplicables a las expresiones.

Como se suele hacer, presentamos tabla de prioridades operaciones, en cada línea de las cuales se recopilan operaciones de la misma prioridad, y las líneas siguen en orden de prioridad, de mayor a menor.

Tabla 3.1. Prioridades de las operaciones del lenguaje C#
Una prioridad Categoría Operaciones Orden
0 Primario (expr), x.y, x->y, f(x), a[x], x++, x--, nuevo, tipo de(t), marcado(expr), sin marcar(expr) De izquierda a derecha
1 unario +, -, !, ~, ++x, --x, (T)x, tamaño de(t) De izquierda a derecha
2 Multiplicativo (Multiplicación) *, /, % De izquierda a derecha
3 Aditivo (suma) +, - De izquierda a derecha
4 Cambio << ,>> De izquierda a derecha
5 Relaciones, verificación de tipos. <, >, <=, >=, es, como De izquierda a derecha
6 Equivalencia ==, != De izquierda a derecha
7 Y lógico (Y) & De izquierda a derecha
8 O lógico exclusivo (XOR) ^ De izquierda a derecha
9 O lógico | De izquierda a derecha
10 Y lógico condicional && De izquierda a derecha
11 O lógico condicional || De izquierda a derecha
12 Expresión condicional ? : De derecha a izquierda
13 Asignación

Pegado con nulo

=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= De derecha a izquierda
14 operador lambda => De derecha a izquierda

Operaciones y métodos de sobrecarga.

Bajo sobrecargar la operación Se entiende la existencia de varias implementaciones de una misma operación. Por ejemplo, la operación "+" se realiza de manera diferente dependiendo de si sus operandos son números enteros, enteros largos, enteros de punto fijo o punto flotante, o cadenas de texto.

Es necesario comprender que las operaciones son caso especial registros de métodos de clase. Los métodos de clase, al igual que las operaciones, pueden sobrecargarse. El método de clase se llama. sobrecargado, si hay varias implementaciones de este método. Los métodos sobrecargados tienen el mismo nombre, pero deben diferir en su firma. La firma del método es una lista de tipos. argumentos formales método. Entonces, dos métodos de clase con el mismo nombre, pero que difieren, por ejemplo, en el número de parámetros, tienen firmas diferentes y satisfacen los requisitos de los métodos sobrecargados.

La mayoría de los operadores de C# están sobrecargados: se puede aplicar el mismo operador a los operandos varios tipos. Por lo tanto, antes de realizar una operación, se busca una implementación que sea adecuada para los tipos de operandos dados. Tenga en cuenta que las operaciones normalmente se realizan con operandos del mismo tipo. Si los operandos diferentes tipos, entonces sucede de antemano conversión de tipo implícita uno de los operandos. Ambos operandos pueden ser del mismo tipo, pero la conversión de tipos aún puede ocurrir porque no existe ningún operador sobrecargado correspondiente para los tipos dados. Esta situación surge con bastante frecuencia en la práctica, ya que, por ejemplo, la operación de suma no está definida para los subtipos inferiores del tipo aritmético. Si no existe una implementación adecuada de la operación para determinados tipos de operandos y no es posible la conversión implícita de tipos de operandos, entonces, como regla general, este error se detecta en la etapa de compilación.

Conversiones de tipos

Cada objeto (variable), cada operando al evaluar una expresión, la expresión en sí se caracteriza por un par que especifica el valor de la expresión y su tipo. En el proceso de cálculo, a menudo surge la necesidad de convertir el tipo: la necesidad de convertir un par a una pareja . El par original se llama fuente de la transformación, el par final se llama objetivo de la transformación.

La necesidad de tales transformaciones surge, como ya se señaló, durante la evaluación de una expresión al convertir los operandos a un tipo consistente con el tipo de operación. La conversión de tipos es necesaria en los operadores de asignación cuando el tipo de expresión del lado derecho del operador se convierte al tipo especificado por el lado izquierdo de este operador. La semántica de asignación también ocurre cuando se llaman métodos en el proceso de reemplazar los argumentos formales del método con parámetros reales. Y aquí es necesaria la conversión de tipos.

Las conversiones de tipos se pueden dividir en seguras y peligrosas. Una conversión segura es aquella en la que se garantiza que:

Una transformación para la que no se cumple al menos una de estas condiciones se denomina peligrosa. Condición suficiente La existencia de una conversión segura es, por ejemplo, una condición de que el tipo sea un subtipo de tipo. De hecho, en este caso, cualquier valor fuente es a la vez valor válido objetivos. Entonces, la transformación de escribe int escribir doble es seguro. Conversión inversa Naturalmente será peligroso.

Algunas conversiones de tipos se realizan automáticamente. Estas conversiones se denominan conversiones implícitas y son comunes al evaluar expresiones. Obviamente, sólo pueden estar implícitas conversiones seguras. Cualquier transformación peligrosa debe ser especificada explícitamente por el propio programador, quien asume toda la responsabilidad de realizar la transformación peligrosa.

Existir diferentes caminos realizar conversiones explícitas: operación de conversión (conversión a tipo), métodos de la clase especial Convert, métodos especiales ToString, Parse. Todos estos métodos serán discutidos en esta conferencia.

Te explicamos cómo se realizan. conversiones implícitas al evaluar una expresión. Supongamos que al calcular alguna expresión es necesario realizar una suma, donde el tipo es double y el tipo es int. Entre las muchas implementaciones de suma se encuentran operaciones que realizan suma en operandos int y suma en operandos dobles, por lo que elegir cualquiera de estas implementaciones de suma requerirá una conversión de tipo de uno de los operandos. Dado que la conversión de int a double es segura, pero el otro método es peligroso, se selecciona la conversión segura, que se realiza automáticamente, el segundo operando se convierte implícitamente al tipo double, se realiza la suma de los operandos de este tipo y el resultado de la suma será de tipo doble.

Organizar un proyecto de software ConsoleExpressions

Como siempre, todos los ejemplos. código de programa, que aparecen en el texto son parte del proyecto de software. Describiré la estructura del proyecto de consola utilizado en esta conferencia, llamado ConsoleExpressions. Además de la clase Programa predeterminada creada, se agregaron al proyecto dos clases denominadas TestingExpressions y Scales. Cada uno de los métodos de la clase TestingExpressions representa una prueba que le permite analizar las características de las operaciones utilizadas para construir expresiones, por lo que esta clase es una colección de pruebas. La clase de Escala es informativa y demuestra cómo trabajar con las escalas que se discutirán en esta conferencia. Para poder llamar a métodos de estas clases, los objetos de estas clases se declaran y crean en el procedimiento Principal de la clase Programa. Estos objetos se utilizan luego como destino para llamar a los métodos apropiados. Esquema general El procedimiento principal y los métodos de clase de llamada son los siguientes:

static void Main(string args) ( string respuesta = "Sí"; do ( try ( TestingExpressions test = new TestingExpressions(); test.Casting(); //Llamar a otros métodos... ) catch (Exception e) ( Console. WriteLine( "¡Es imposible continuar trabajando normalmente!"); Console.WriteLine(e.Message); Console.WriteLine("¿Seguimos trabajando? (Sí/no)"); (respuesta == "Sí" || respuesta == "sí" || respuesta == "sí");

Siempre que sea necesario dar un ejemplo de código en el texto de la conferencia, ya sea texto completo el método que se llama, como el método Casting, o un fragmento separado del método.

Para evaluar correctamente expresiones (como 4 + 2 * 3), debemos saber qué operadores significan qué y en qué orden deben aplicarse. Esta secuencia en la que se ejecutan se llama prioridad de operaciones. Siguiente reglas normales matemáticas (en las que la multiplicación debe hacerse antes de la suma), la expresión anterior se resuelve como - 4 + (2 * 3), el resultado es el valor 10.

En C++, todos los operadores (operaciones) tienen su propio nivel de prioridad. Primero se ejecutan aquellos en los que es superior. En la siguiente tabla puedes ver que la prioridad de las operaciones de multiplicación y división (5) es mayor que la de las operaciones de suma y resta (6). El compilador usa esto para determinar el orden en que se procesan las expresiones.

Pero ¿qué pasa si dos operadores en una expresión tienen el mismo nivel de prioridad y están colocados uno al lado del otro? ¿Qué operación deberías realizar primero? Y aquí el compilador usará reglas de asociatividad, que indican la dirección de las operaciones: de izquierda a derecha o de derecha a izquierda. Por ejemplo, en 3 * 4/2, las operaciones de multiplicación y división tienen el mismo nivel de prioridad: 5. Y el nivel de asociatividad 5 es de izquierda a derecha, así que lo resolveremos así: (3 * 4) / 2 = 6.

Tabla de prioridad de operación

Notas:

1 es el nivel de prioridad más alto y 17 es el más bajo. Transacciones con más nivel alto La prioridad se ejecuta primero.

L -> R significa de izquierda a derecha.

R -> L significa de derecha a izquierda.

asociatividad Operador Descripción Ejemplo
1. Sí :: Alcance global (unario) ::nombre
:: Ámbito de clase (binario) nombre_clase::nombre_miembro
2. L->R () Entre paréntesis (expresión)
() Llamar a una función nombre_función(parámetros)
() Inicialización escriba el nombre (expresión)
{} Inicialización uniforme (C++11) escriba el nombre (expresión)
tipo() elenco funcional nuevo_tipo(expresión)
tipo() Reparto funcional (C++11) nuevo_tipo(expresión)
índice de matriz puntero
. Accediendo a un miembro de objeto objeto.nombre_miembro
-> Acceder a un miembro de objeto mediante un puntero puntero_objeto->nombre_miembro
++ Post-incremento valorl++
–– Post-decremento valor l––
mecanografiado Información de tipo de tiempo de ejecución typeid(tipo) o typeid(expresión)
const_cast Desechar la constante const_cast(expresión)
transmisión_dinámica Transmisión con verificación de tipo en tiempo de ejecución emisión_dinámica(expresión)
reinterpretar_cast Transmitir un tipo a otro reinterpret_cast(expresión)
transmisión_estática Transmisión con verificación de tipo en tiempo de compilación static_cast(expresión)
3. D->L + más unario +expresión
menos unario -expresión
++ Pre-incremento ++lvalor
–– Pre-decremento ––lvalor
! NO lógico (NO) !expresión
~ Bit a bit NO (NO) ~ expresión
(tipo) elenco estilo C (nuevo_tipo)expresión
tamaño de Tamaño en bytes tamaño de (tipo) o tamaño de (expresión)
& DIRECCIÓN &lvalor
* Desreferencia *expresión
nuevo Asignación de memoria dinámica nuevo tipo
nuevo Asignación de matriz dinámica nuevo tipo
borrar Eliminación de memoria dinámica eliminar puntero
borrar Eliminación de matriz dinámica eliminar puntero
4. L->R ->* Selector de puntero de miembro puntero_objeto->*puntero_a_miembro
.* Selector de objetos miembro objeto.*puntero_a_miembro
5. L->R * Multiplicación expresión * expresión
/ División expresión / expresión
% Resto expresión % expresión
6. L->R + Suma expresión + expresión
Sustracción expresión - expresión
7. L->R << Desplazamiento bit a izquierda expresión<< expression
>> Desplazamiento bit a bit a la derecha expresión >> expresión
8. L->R < Comparación. Menos que expresión< expression
<= Comparación. Menor o igual expresión<= expression
> Comparación. Más que expresión > expresión
>= Comparación. Mayor que o igual expresión >= expresión
9. L->R == igual expresión == expresión
!= No es igual expresión != expresión
10. L->R & Bit a bit Y expresión y expresión
11. L->R ^ OR exclusivo bit a bit (XOR) expresión ^ expresión
12. L->R | O bit a bit expresión | expresión
13. L->R && Y lógico (Y) expresión && expresión
14. L->R || O lógico expresión || expresión
15. R->L ?: Operador condicional ternario (ver nota a continuación) expresión ? expresión: expresión
= Asignación valor l = expresión
*= Multiplicación con asignación valor l *= expresión
/= División con asignación valor l /= expresión
%= División con resto con asignación valor l% = expresión
+= Suma con asignación valor l += expresión
-= Resta con tarea valor l -= expresión
<<= Asignación de desplazamiento a la izquierda bit a bit valor l<<= expression
>>= Asignación de desplazamiento a la derecha bit a bit valor l >>= expresión
&= Asignación con operación AND bit a bit valor l &= expresión
|= Asignación con operación OR bit a bit valorl |= expresión
^= Asignación con operación OR exclusiva bit a bit (XOR) valor l ^ = expresión
16. R->L tirar Crear una excepción manualmente lanzar expresión
17. L->R , Operador de coma (coma) expresión, expresión

Nota: ¿Una expresión en medio de una declaración condicional?: se ejecuta como si estuviera entre paréntesis.

Algunos operadores que ya conoces: +, -, *, /, (), =,<,>, <= и >=. Sus significados son los mismos tanto en matemáticas como en C++.

Sin embargo, si no tiene experiencia con otros lenguajes de programación, la mayoría de estos operadores no le resultarán claros en este momento. Esto esta bien. consideraremos mayoría de ellos en este capítulo, y hablaremos del resto según sea necesario.

Esta tabla está pensada principalmente para que puedas consultarla en cualquier momento para resolver Posibles problemas prioridad o asociatividad.

¿Cómo elevar a una potencia en C++?

Ya deberías haber notado que el operador ^, que se usa comúnmente para representar la exponenciación en matemáticas ordinarias, no lo es en C++. En C++ esto es operación bit a bit XOR. ¿Entonces qué en lugar de ^? En cambio, la función pow(), que se encuentra en archivo de cabecera :

#incluir doble x = pow(3.0, 4.0); // 3 elevado a 4

#incluir

doble x = poder (3.0, 4.0); // 3 elevado a 4

Tenga en cuenta que los parámetros y valores de retorno de la función pow() son de tipo doble. Y dado que los tipos de punto flotante son conocidos por sus errores de redondeo, los resultados de pow() pueden ser ligeramente inexactos (un poco menos o un poco más).

Si necesita elevar un número entero a una potencia, entonces es mejor usar propia función, Por ejemplo:

// nota: el exponente no debe ser negativo int pow(int base, int exp) ( int resultado = 1; while (exp) ( if (exp & 1) resultado *= base; exp >>= 1; base *= base; ) devolver resultado;

// nota: el exponente no debe ser negativo

int potencia(int base, int exp)

resultado entero = 1;

mientras(exp)

si (exp & 1)

resultado * = base ;

exp >> = 1 ;

base* = base;

resultado de retorno;

El algoritmo utilizado aquí es "Exponciación al cuadrado".

No te preocupes si algo no queda claro. Sólo tenga en cuenta el problema de desbordamiento que puede ocurrir si uno de los argumentos es demasiado grande.

Prueba

1) De las matemáticas escolares sabes que las expresiones entre paréntesis se ejecutan primero. Por ejemplo, en (2 + 3) * 4, la parte (2 + 3) se ejecutará primero.

Hay 4 expresiones en esta tarea a las que les faltan paréntesis. Utilizando las reglas de precedencia de operadores y asociatividad de la tabla anterior, agregue paréntesis a cada expresión como si fueran procesadas por el compilador.

Clave: Usar columna Ejemplo en la tabla anterior para determinar si el operador es unario (tiene un operando) o binario (dos operandos). Si olvidó qué es unario o binario, consulte lección 17.

Solución de ejemplo: x = 2 + 3% 4

El operador binario % tiene mayor prioridad que el operador + o =, por lo que se aplica primero: x = 2 + (3 % 4);

El operador binario + tiene mayor prioridad que =, por lo que se utiliza a continuación.

Tareas

a) x = 3 + 4 + 5;
b) x = y = z;
c) z *= ++y + 5;
d) un || b && c || d;

Respuesta

A) El nivel de precedencia del operador binario + es mayor que el de =:

x = (3 + 4 + 5);

Asociatividad del operador binario + de izquierda a derecha:

Respuesta: x = ((3 + 4) + 5).

b) Asociatividad del operador binario = de derecha a izquierda:

Respuesta: x = (y = z).

V) operador unario++ tiene la máxima prioridad:

El operador binario + tiene la segunda prioridad más alta:

Respuesta: z *= ((++y) + 5).

GRAMO) El operador binario && tiene mayor prioridad que ||:

un || (b && c) || d;

Asociatividad del operador binario || de izquierda a derecha:

Respuesta: (a || (b && c)) || d.

C++ para principiantes

4.13. Prioridades

Las prioridades de operación especifican la secuencia de cálculos en una expresión compleja. Por ejemplo, ¿qué valor obtendrá ival?

Int ival = 6 + 3 * 4 / 2 + 2;

Si calculas las operaciones de izquierda a derecha, obtienes 20. Otros resultados posibles incluyen 9, 14 y 36. La respuesta correcta es 14.
En C++, la multiplicación y la división tienen mayor prioridad que la suma, por lo que se evaluarán primero. Sus propias prioridades son iguales, por lo que la multiplicación y la división se evaluarán de izquierda a derecha. Así, el orden de cálculo expresión dada es:

1. 3 * 4 => 12 2. 12 / 2 => 6 3. 6 + 6 => 12 4. 12 + 2 => 14

El siguiente diseño no se comporta como cabría esperar. La prioridad de la operación de asignación es menor que la de la operación de comparación:

Mientras (ch = nextChar() != "\n")

El programador quería asignar un valor a la variable ch y luego comprobar si era igual al carácter nueva línea. Sin embargo, la expresión en realidad primero compara el valor devuelto por nextChar() con "\n" y asigna el resultado (verdadero o falso) a la variable ch.
Las prioridades de operación se pueden cambiar usando paréntesis. Las expresiones entre paréntesis se evalúan primero. Por ejemplo:

4 * 5 + 7 * 2 ==> 34 4 * (5 + 7 * 2) ==> 76 4 * ((5 + 7) * 2) ==> 96

A continuación se explica cómo utilizar paréntesis para corregir el comportamiento del ejemplo anterior:

Mientras ((ch = nextChar()) != "\n")

Los operadores tienen y prioridad, Y asociatividad. El operador de asignación es asociativo por la derecha, por lo que se evalúa de derecha a izquierda:

Ival = jval = kva1 = lval

Primero kval obtiene el valor de lval, luego jval obtiene el valor del resultado de esa asignación y finalmente ival obtiene el valor de jval.
Las operaciones aritméticas, por el contrario, son asociativas por la izquierda. Por tanto, en la expresión

Ival + jval + kva1 + 1va1

Primero se agregan ival y jval, luego se agrega kval al resultado y luego lval.
La tabla 4.4 muestra Lista llena Operadores de C++ en orden de precedencia descendente. Los operadores dentro de la misma sección de la tabla tienen la misma prioridad. Todos los operadores de una sección tienen mayor prioridad que los operadores de las secciones siguientes. Por tanto, las operaciones de multiplicación y división tienen la misma prioridad y es mayor que la prioridad de cualquiera de las operaciones de comparación.

Ejercicio 4.18

¿Cuál es el orden de cálculo? siguientes expresiones? Utilice la tabla 4.4 para responder.

(a)! ptr == ptr->siguiente (b) ~ uc ^ 0377 & ui<< 4 (c) ch = buf[ bp++ ] != "\n"

Ejercicio 4.19

Las tres expresiones del ejercicio anterior se evalúan en un orden diferente al que aparentemente pretendía el programador. Organice los corchetes para lograr su intención original.

Ejercicio 4.20

Las siguientes expresiones provocan un error de compilación debido a una precedencia de operadores mal entendida. Explique cómo corregirlos utilizando la Tabla 4.4.

(a) int i = hacer algo(), 0; (b)cout<< ival % 2 ? "odd" : "even";

Tabla 4.4. Prioridades de operación

Operador Significado Uso
:: Alcance global ::nombre
:: Alcance de la clase nombre de la clase
:: Alcance del espacio de nombres espacio de nombres::nombre
. Acceso de miembros objeto.miembro
-> Acceder a un miembro mediante puntero puntero->miembro
tomando el indice variable
() Llamar a una función nombre(lista_expr)
() Construcción de significado tipo(lista_expr)
++ incremento de sufijo valorl++
decremento del sufijo valor--
mecanografiado identificador de tipo typeid(tipo)
mecanografiado identificador de tipo de expresión typeid(expr)
conversión de tipo const_cast (expr.)
conversión de tipo transmisión_dinámica (expr.)
reinterpretar_cast fundición reinterpretar_cast (expr.)
transmisión_estática fundición transmisión_estática (expr.)
tamaño de tamaño del objeto tamaño de expr
tamaño de tipo de letra tamaño de (tipo)
++ incremento de prefijo ++lvalor
-- disminución del prefijo --lvalor
~ bit a bit NO ~expr
! NO lógico !expr
- menos unario -expr
+ unario más +expr
* desreferenciación *expr
& DIRECCIÓN &expr
() fundición (tipo)expr
nuevo asignación de memoria nuevo tipo
nuevo asignación de memoria e inicialización nuevo tipo (listaexpr)
nuevo Asignación de memoria para una matriz todas las formas
borrar liberando memoria todas las formas
borrar liberar memoria de una matriz todas las formas
->* acceder a un miembro de la clase por puntero puntero-> *puntero_a_miembro
.* acceder a un miembro de la clase por puntero objeto.*puntero_a_miembro
* Multiplicación expr * expr
/ División expr/expr
% división de módulo expresión % expresión
+ suma expr + expr
- sustracción expr - expr
<< desplazamiento a la izquierda exprés<< expr
>> cambio a la derecha expresión >> expresión
< menos exprés< expr
<= menos o igual exprés<= expr
> más expr > expr
>= más o igual expresión >= expresión
== es igual expr == expr
!= no es igual expr != expr
& bit a bit Y expr y expr
^ bit a bit EXCLUSIVO O expr^expr
| bit a bit O expr | exprés
&& lógico Y expr && expr
|| O lógico expresión || exprés
?: operador condicional ¿expr? expr * expr
= asignación valor l = expr
=, *=, /=, %=, +=, -=, <<=, >>=, &=, |=, ^= asignación compuesta valor l += expr, etc.
tirar planteando una excepción tirar expr
, coma expr, expr

Orden de prioridad y ejecución

La precedencia y asociatividad de los operadores de C influyen en el orden en que se agrupan los operandos y se evalúan las operaciones en una expresión. La prioridad de las operaciones sólo es relevante cuando existen varias operaciones que tienen diferentes prioridades. Primero se evalúan las expresiones con operadores de mayor prioridad.

La Tabla 4.1 enumera las operaciones en orden de prioridad descendente. Las operaciones ubicadas en la misma fila de la tabla, o combinadas en un grupo, tienen la misma prioridad y la misma asociatividad.

Tabla 4.1.

Prioridad y asociatividad de operaciones en lenguaje C.

señal de operación Nombre asociatividad
() . -> Primario De izquierda a derecha
+ - ~ ! * & ++ - tamaño del tipo de reparto unario De derecha a izquierda
* / % multiplicativo De izquierda a derecha
+ - Aditivo De izquierda a derecha
>> << Cambio De izquierda a derecha
< > <= >= Actitud De izquierda a derecha
== != Actitud De izquierda a derecha
& Bit a bit Y De izquierda a derecha
^ O exclusivo bit a bit De izquierda a derecha
| O inclusivo bit a bit De izquierda a derecha
&& Y lógico De izquierda a derecha
|| O lógico De izquierda a derecha
?: Condicional De derecha a izquierda
= *= /= %= += -= <<= >>= &= |= ^= Asignación simple y compuesta De derecha a izquierda
, Cálculo secuencial De izquierda a derecha

De la tabla 4.1. De ello se deduce que los operandos que representan la llamada a función, la expresión de índice, la expresión de selección de elementos y la expresión entre paréntesis tienen la mayor precedencia y asociatividad de izquierda a derecha. La conversión de tipos tiene la misma precedencia y orden de ejecución que los operadores unarios.

Una expresión puede contener varias operaciones de la misma prioridad. Cuando aparecen varios operadores con el mismo nivel de prioridad en una expresión, se aplican según su asociatividad: de derecha a izquierda o de izquierda a derecha.

Cabe señalar que el lenguaje C adopta un orden de precedencia desafortunado para algunas operaciones, en particular para las operaciones de desplazamiento y bit a bit. Tienen menor prioridad que las operaciones aritméticas (suma, etc.). Por lo tanto la expresión

a = by 0xFF + 5

calculado como

a = b & (0xFF + 5),

y la expresión

a+c >> 1

calculado como

(a+c) >> 1

Las operaciones multiplicativas, aditivas y bit a bit tienen la propiedad de conmutatividad. Esto significa que el resultado de evaluar una expresión que incluye varias operaciones conmutativas de la misma prioridad no depende del orden en que se realizan estas operaciones. Por lo tanto, el compilador se reserva el derecho de evaluar dichas expresiones en cualquier orden, incluso si la expresión contiene paréntesis que especifican el orden de evaluación.

SP TS implementa la operación unaria más, que le permite garantizar el orden de cálculo de las expresiones entre paréntesis.

Operación de cálculo secuencial, operaciones lógicas Y y O, operación condicional y garantía de operación de llamada de función un cierto orden cálculos de sus operandos. Una operación de evaluación secuencial garantiza que sus operandos se evalúen por turnos, de izquierda a derecha (una coma que separa los argumentos en una llamada de función no es una operación de evaluación secuencial y no proporciona tales garantías). Solo se garantiza que en el momento en que se llame a la función, todos los argumentos ya se hayan calculado.

Una operación condicional evalúa primero su primer operando y luego, dependiendo de su valor, el segundo o el tercero.

Las operaciones lógicas también evalúan sus operandos de izquierda a derecha. Sin embargo, las operaciones lógicas evalúan la cantidad mínima de operandos necesarios para determinar el resultado de una expresión. Por tanto, es posible que el segundo operando de la expresión no se evalúe en absoluto.

int x, y, z, f();

z = x > y || f(x,y);

Primero, se calcula la expresión x>y. Si es cierto, entonces a la variable z se le asigna el valor 1 y no se llama a la función f. Si el valor de x no es mayor que y, entonces se calcula la expresión f(x,y). Si la función f devuelve un valor distinto de cero, entonces a la variable z se le asigna 1; de lo contrario, 0. Tenga en cuenta también que al llamar a la función f, se garantiza que el valor de su primer argumento sea mayor que el segundo.

El ejemplo considerado muestra las principales posibilidades de utilizar el orden de ejecución de operaciones lógicas. Se trata, en primer lugar, de un aumento de la eficiencia al colocar las condiciones más probables como primeros operandos de las operaciones lógicas. En segundo lugar, es posible insertar comprobaciones en una expresión; si son falsas, no se realizarán acciones posteriores. Entonces, en la próxima operador condicional si La lectura del siguiente carácter del archivo sólo se realizará si aún no se ha llegado al final del archivo:

si(!feof(pf)) && (c = obtenerc(pf)) ...

Aquí feof- función de verificación de fin de archivo, getc- función para leer un símbolo de un archivo (ver sección 12).

En tercer lugar, podemos garantizar que en la expresión f(x)&&g(y) función F será llamado antes de la función gramo. Para expresión f(x)+g(y) Esto no se puede decir.

Los siguientes ejemplos muestran la agrupación de operandos para varias expresiones.

Expresión Agrupación de operandos
a&b || C (a y b) || C
a = b || C a = (b || c)
preguntas && r || s-- (q && r) || (s--)
pag == 0 ? pag+= 1: pag+= 2 (p == 0 ? p += 1: p) += 2

En el primer ejemplo operación bit a bit Y (&) tiene mayor prioridad que - operación lógica O (||), entonces la expresión a&b es el primer operando de la operación lógica OR.

En el segundo ejemplo, el operador lógico OR (||) tiene mayor prioridad que el operador de asignación simple, por lo que la expresión b||c forma el operando derecho de la operación de asignación. (Tenga en cuenta que el valor asignado A, es cero o uno).

El orden de las operaciones al calcular el valor de una expresión está determinado por disposición de señales de operación, paréntesis Y prioridad de operaciones . Las operaciones con mayor prioridad se realizan primero. Si una expresión contiene varias operaciones de la misma prioridad en el mismo nivel, se procesan de acuerdo con el orden de ejecución: de derecha a izquierda o de izquierda a derecha. Si necesita cambiar el orden de las operaciones en una expresión, debe usar paréntesis, por ejemplo (x + y) * z .

Una prioridad operaciones de coma más bajo que todas las demás operaciones.

La siguiente tabla enumera las operaciones del lenguaje C++ en orden de prioridad descendente. Las operaciones con diferentes prioridades están separadas por una línea.

Tabla de prioridades de operación

Señales de operación

Nombres de operaciones

Orden de ejecución

aumento de prioridad

incremento de sufijo

decremento del sufijo

de izquierda a derecha

tamaño de

( tipo ) expresión y

tipo (expresión)

tamaño del operando en bytes

incremento de prefijo

disminución del prefijo

bit a bit norte mi

lógico NO

menos unario, más

conversión de tipo

a la derecha izquierda

multiplicación

resto después de la división de números enteros

de izquierda a derecha

suma

sustracción

de izquierda a derecha

desplazamiento a la izquierda

cambio a la derecha

de izquierda a derecha

menos o igual

más o igual

de izquierda a derecha

de izquierda a derecha

bit a bit Y

de izquierda a derecha

exclusivo bit a bit O

de izquierda a derecha

bit a bit O

de izquierda a derecha

lógico Y

de izquierda a derecha

lógico O

de izquierda a derecha

? :

condicional

a la derecha izquierda

*= , /= , %=

+= , - =

<<= , >>=

&= , |= , ^=

tarea (simple y

compuesto)

a la derecha izquierda

operación de coma

de izquierda a derecha

Tipo de fundición

Lenguaje de programación C++, al ser un lenguaje mecanografiado, permite manejar expresiones que operan en varios tipos de datos con mucha libertad. En este caso, los operandos de la expresión se convierten a algún tipo común.

Solo las conversiones que convierten operandos con un rango de valores menor en operandos con un rango de valores mayor se realizan automáticamente, ya que esto ocurre sin pérdida de información. Por ejemplo, si en la expresión ival + fvAlabama variable ival tipo En t y la variable FvAlabama- tipo flotar , luego al ejecutar operaciones(+ ) valor variable IVAlabama se emitirá para escribir flotar .

Las expresiones que pueden perder información, como cuando se asignan números enteros largos a números enteros más cortos o reales, pueden generar advertencias, pero son válidas (consulte el operador de asignación).

Para cualquier expresión, puede especificar explícitamente una conversión de su tipo utilizando un operador unario llamado trayendo (por transformación) tipo . La operación se puede escribir en dos formatos:

(tipo) expresión

tipo(expresión)

Operando operacionestipo moldes es la expresión a convertir. Una prioridad operaciones de conversión de tipos Lo mismo que otras operaciones unarias. Por ejemplo: (largodoble) 5; (En t) F ; (doble) a/2 .

Si la expresión en cuestión tiene suficiente mirada compleja, es recomendable ponerlo entre paréntesis para asegurarse de que se cambiará el tipo de resultado de toda la expresión, y no solo de una parte. Por ejemplo,

(En t) x+b*c

(En t) (x + b * c )

En el primer caso, la transformación es relativa a la variable. X , en el segundo – a toda la expresión X+b*c.




Arriba