sirve significa que poner para operadores operador incremento ejemplos definicion decremento como c++ c increment prefix

significa - La diferencia entre C y C++ con respecto al operador++



para que sirve++ en c++ (2)

He estado jugando con un código y vi algo de lo que no entiendo el "por qué".

int i = 6; int j; int *ptr = &i; int *ptr1 = &j j = i++; //now j == 6 and i == 7. Straightforward.

¿Qué pasa si coloca el operador en el lado izquierdo del signo igual?

++ptr = ptr1;

es equivalente a

(ptr = ptr + 1) = ptr1;

mientras

ptr++ = ptr1;

es equivalente a

ptr = ptr + 1 = ptr1;

El postfix ejecuta un error de compilación y lo obtengo. Tienes un "ptr + 1" constante en el lado izquierdo de un operador de asignación. Lo suficientemente justo.

El prefijo uno compila y FUNCIONA en C ++. Sí, entiendo que es desordenado y está lidiando con memoria no asignada, pero funciona y se compila. En C esto no se compila, devolviendo el mismo error que el postfix "lvalue required as left operand of task". Esto sucede sin importar cómo esté escrito, expandido con dos operadores "=" o con la sintaxis "++ ptr".

¿Cuál es la diferencia entre cómo C maneja tal asignación y cómo C ++ la maneja?


En C, el resultado del incremento previo y posterior son valores y no podemos asignar un valor r , necesitamos un valor l ( ver también: Comprensión de valores y valores en C y C ++ ). Podemos ver yendo al borrador de la sección estándar C11 6.5.2.4 Operadores de incremento y decremento de Postfix que dice ( énfasis mío en adelante ):

El resultado del operador postfix ++ es el valor del operando. [...] Consulte las discusiones sobre operadores aditivos y asignación compuesta para obtener información sobre restricciones, tipos y conversiones y los efectos de las operaciones en los punteros. [...]

Por lo tanto, el resultado del incremento posterior es un valor que es sinónimo de rvalue y podemos confirmarlo yendo a la sección 6.5.16 Operadores de asignación a los que nos señala el párrafo anterior para una mayor comprensión de las restricciones y los resultados, dice:

[...] Una expresión de asignación tiene el valor del operando izquierdo después de la asignación, pero no es un valor l . [...]

lo que confirma además que el resultado del post-incremento no es un valor.

Para pre-incremento podemos ver en la sección 6.5.3.1 operadores de incremento y decremento de prefijo que dice:

[...] Consulte las discusiones sobre operadores aditivos y asignación compuesta para obtener información sobre restricciones, tipos, efectos secundarios y conversiones y los efectos de las operaciones en los punteros.

también apunta de nuevo a 6.5.16 como lo hace el incremento posterior y, por lo tanto, el resultado del incremento previo en C tampoco es un valor.

En C ++, el post-incremento también es un valor r , más específicamente un valor prva podemos confirmar esto yendo a la sección 5.2.6 Incremento y decremento que dice:

[...] El resultado es un prvalue. El tipo del resultado es la versión no calificada por cv del tipo del operando [...]

Con respecto al pre-incremento C y C ++ difieren. En C el resultado es un valor r mientras que en C ++ el resultado es un valor l que explica por qué ++ptr = ptr1; funciona en C ++ pero no en C.

Para C ++ esto se trata en la sección 5.3.2 Incremento y disminución que dice:

[...] El resultado es el operando actualizado; es un valor l , y es un campo de bits si el operando es un campo de bits. [...]

Para entender si:

++ptr = ptr1;

está bien definido o no en C ++, necesitamos dos enfoques diferentes, uno para pre C ++ 11 y otro para C ++ 11.

Pre C ++ 11 esta expresión invoca un comportamiento indefinido , ya que está modificando el objeto más de una vez dentro del mismo punto de secuencia. Podemos ver esto yendo a un borrador de Pre C ++ 11 estándar sección 5 Expresiones que dice:

Excepto donde se indique, el orden de evaluación de los operandos de operadores individuales y subexpresiones de expresiones individuales, y el orden en que se producen los efectos secundarios, no está especificado.57) Entre el punto de secuencia anterior y siguiente, un objeto escalar tendrá modificado su valor almacenado a lo sumo una vez por la evaluación de una expresión. Además, se debe acceder al valor anterior solo para determinar el valor a almacenar. Los requisitos de este párrafo se cumplirán para cada ordenamiento permitido de las subexpresiones de una expresión completa; de lo contrario, el comportamiento es indefinido. [Ejemplo:

i = v[i ++]; / / the behavior is undefined i = 7 , i++ , i ++; / / i becomes 9 i = ++ i + 1; / / the behavior is undefined i = i + 1; / / the value of i is incremented

—Ejemplo]

Estamos incrementando ptr y luego asignándole posteriormente, que son dos modificaciones y en este caso el punto de secuencia ocurre al final de la expresión después de ; .

Para C + 11, debemos ir al informe de defectos 637: las reglas de secuencia y el ejemplo no están de acuerdo sobre cuál fue el informe de defectos que resultó en:

i = ++i + 1;

convirtiéndose en un comportamiento bien definido en C ++ 11 mientras que antes de C ++ 11 este era un comportamiento indefinido . La explicación en este informe es una de las mejores que he visto y leerla muchas veces fue esclarecedora y me ayudó a comprender muchos conceptos bajo una nueva luz.

La lógica que lleva a esta expresión a convertirse en un comportamiento bien definido es la siguiente:

  1. El efecto secundario de la asignación se debe secuenciar después de los cálculos de valor tanto de su LHS como de su RHS (5.17 [expr.ass] párrafo 1).

  2. El LHS (i) es un valor l, por lo que su cálculo de valor implica calcular la dirección de i.

  3. Para calcular el valor de RHS (++ i + 1), es necesario calcular primero el valor de la expresión lvalue ++ i y luego hacer una conversión lvalue-to-rvalue en el resultado. Esto garantiza que el efecto secundario de incremento se secuencia antes del cálculo de la operación de adición, que a su vez se secuencia antes del efecto secundario de asignación. En otras palabras, produce un orden bien definido y un valor final para esta expresión.

La lógica es algo similar para:

++ptr = ptr1;

  1. Los cálculos del valor de LHS y RHS se secuencian antes del efecto secundario de la asignación.

  2. El RHS es un valor l, por lo que su cálculo de valor implica calcular la dirección de ptr1.

  3. Para calcular el valor del LHS (++ ptr), primero es necesario calcular el valor de la expresión lvalue ++ ptr y luego hacer una conversión lvalue-to-rvalue en el resultado. Esto garantiza que el efecto secundario de incremento se secuencia antes del efecto secundario de asignación. En otras palabras, produce un orden bien definido y un valor final para esta expresión.

Nota

El OP dijo:

Sí, entiendo que es desordenado y está lidiando con memoria no asignada, pero funciona y se compila.

Los punteros a objetos sin matriz se consideran matrices de tamaño uno para operadores aditivos, voy a citar el borrador del estándar C ++, pero C11 tiene casi el mismo texto. De la sección 5.7 Operadores aditivos :

Para los fines de estos operadores, un puntero a un objeto sin matriz se comporta igual que un puntero al primer elemento de una matriz de longitud uno con el tipo de objeto como su tipo de elemento.

y además nos dice que señalar uno más allá del final de una matriz es válido siempre que no desreferencia el puntero:

[...] Si tanto el operando del puntero como el resultado apuntan a elementos del mismo objeto de matriz, o uno pasado el último elemento del objeto de matriz , la evaluación no producirá un desbordamiento; de lo contrario, el comportamiento es indefinido.

entonces:

++ptr ;

sigue siendo un puntero válido


Tanto en C como en C ++, el resultado de x++ es un valor r, por lo que no puede asignarlo.

En C, ++x es equivalente a x += 1 (C estándar §6.5.3.1 / p2; todas las citas estándar de C son para WG14 N1570). En C ++, ++x es equivalente a x += 1 si x no es un bool (estándar C ++ §5.3.2 [expr.pre.incr] / p1; todas las citas estándar C ++ son para WG21 N3936).

En C, el resultado de una expresión de asignación es un valor r (C estándar §6.5.16 / p3):

Un operador de asignación almacena un valor en el objeto designado por el operando izquierdo. Una expresión de asignación tiene el valor del operando izquierdo después de la asignación, pero no es un valor l.

Debido a que no es un valor l, no puede asignarle: (C estándar §6.5.16 / p2 - tenga en cuenta que esto es una restricción)

Un operador de asignación tendrá un valor l modificable como su operando izquierdo.

En C ++, el resultado de una expresión de asignación es un valor l (estándar C ++ §5.17 [expr.ass] / p1):

El operador de asignación (=) y los operadores de asignación compuesta se agrupan de derecha a izquierda. Todos requieren un valor l modificable como su operando izquierdo y devuelven un valor l que se refiere al operando izquierdo.

Entonces ++ptr = ptr1; es una violación de restricción diagnosticable en C, pero no viola ninguna regla diagnosticable en C ++.

Sin embargo, pre-C ++ 11, ++ptr = ptr1; tiene un comportamiento indefinido, ya que modifica ptr dos veces entre dos puntos de secuencia adyacentes.

En C ++ 11, el comportamiento de ++ptr = ptr1 vuelve bien definido. Es más claro si lo reescribimos como

(ptr += 1) = ptr1;

Desde C ++ 11, el estándar C ++ proporciona eso (§5.17 [expr.ass] / p1)

En todos los casos, la asignación se secuencia después del cálculo del valor de los operandos derecho e izquierdo, y antes del cálculo del valor de la expresión de asignación. Con respecto a una llamada de función secuenciada indeterminadamente, la operación de una asignación compuesta es una evaluación única.

Entonces, la asignación realizada por = se secuencia después del cálculo del valor de ptr += 1 y ptr1 . La asignación realizada por += se secuencia antes del cálculo del valor de ptr += 1 , y todos los cálculos de valor requeridos por el += se secuencian necesariamente antes de esa asignación. Por lo tanto, la secuencia aquí está bien definida y no hay un comportamiento indefinido.