rango - libreria random c++
¿Qué significa i=(i,++ i, 1)+1; ¿hacer? (7)
Después de leer esta respuesta sobre comportamiento indefinido y puntos de secuencia, escribí un pequeño programa:
#include <stdio.h>
int main(void) {
int i = 5;
i = (i, ++i, 1) + 1;
printf("%d/n", i);
return 0;
}
La salida es
2
.
¡Oh Dios, no vi venir el decremento!
¿Que está sucediendo aquí?
Además, mientras compilaba el código anterior, recibí una advertencia que decía:
px.c: 5: 8: advertencia: el operando de la izquierda de la expresión de coma no tiene efecto
[-Wunused-value] i = (i, ++i, 1) + 1; ^
¿Por qué? Pero probablemente será respondido automáticamente por la respuesta de mi primera pregunta.
Citando de
C11
, capítulo
6.5.17
,
operador de coma
El operando izquierdo de un operador de coma se evalúa como una expresión vacía; Hay un punto de secuencia entre su evaluación y la del operando correcto. Luego se evalúa el operando correcto; El resultado tiene su tipo y valor.
Entonces, en tu caso,
(i, ++i, 1)
se evalúa como
-
i
, se evalúa como una expresión vacía, valor descartado -
++i
, se evalúa como una expresión vacía, valor descartado -
finalmente,
1
, valor devuelto.
Entonces, la declaración final parece
i = 1 + 1;
y llego a
2
.
Supongo que esto responde a sus dos preguntas,
- ¿Cómo obtengo un valor 2?
- ¿Por qué hay un mensaje de advertencia?
Nota: FWIW, como hay un
punto de secuencia
presente después de la evaluación del operando de la izquierda, una expresión como
(i, ++i, 1)
no invocará a UB, como generalmente se
puede
pensar por error.
Debe saber qué está haciendo el operador de coma aquí:
Tu expresión:
(i, ++i, 1)
Se evalúa la primera expresión,
i
, se evalúa la segunda expresión,
++i
, y se devuelve la tercera expresión,
1
, para toda la expresión.
Entonces el resultado es:
i = 1 + 1
.
Para su pregunta extra, como puede ver, la primera expresión no tiene ningún efecto, por lo que el compilador se queja.
El resultado de
(i, ++i, 1)
es
1
por
(i,++i,1)
la evaluación ocurre de tal manera que el operador descarta el valor evaluado y retendrá el valor más correcto, que es
1
Entonces
i = 1 + 1 = 2
En la expresión
(i, ++i, 1)
, la coma utilizada es el
operador de coma
el operador de coma (representado por el token) es un operador binario que evalúa su primer operando y descarta el resultado, y luego evalúa el segundo operando y devuelve este valor (y tipo).
Debido a que descarta su primer operando, generalmente solo es útil cuando el primer operando tiene efectos secundarios deseables . Si no se produce el efecto secundario del primer operando, el compilador puede generar una advertencia sobre la expresión sin efecto.
Entonces, en la expresión anterior, se evaluará el
i
más a la izquierda y se descartará su valor.
Entonces
++i
será evaluado e incrementará
i
en 1 y nuevamente el valor de la expresión
++i
será descartado,
pero el efecto secundario a
i
es permanente
.
Entonces
1
será evaluado y el valor de la expresión será
1
.
Es equivalente a
i; // Evaluate i and discard its value. This has no effect.
++i; // Evaluate i and increment it by 1 and discard the value of expression ++i
i = 1 + 1;
Tenga en cuenta que la expresión anterior es perfectamente válida y no invoca un comportamiento indefinido porque hay un punto de secuencia entre la evaluación de los operandos izquierdo y derecho del operador de coma.
Encontrarás una buena lectura en la página wiki para el operador de coma .
Básicamente
... evalúa su primer operando y descarta el resultado, y luego evalúa el segundo operando y devuelve este valor (y tipo).
Esto significa que
(i, i++, 1)
a su vez, evaluará
i
, descartará el resultado, evaluará
i++
, descartará el resultado y luego evaluará y devolverá
1
.
La coma tiene una precedencia "inversa". Esto es lo que obtendrá de libros antiguos y manuales en C de IBM (70s / 80s). Entonces, el último ''comando'' es lo que se usa en la expresión principal.
En la C moderna, su uso es extraño, pero es muy interesante en la antigua C (ANSI):
do {
/* bla bla bla, consider conditional flow with several continue''s */
} while ( prepAnything(), doSomethingElse(), logic_operation);
Si bien todas las operaciones (funciones) se invocan de izquierda a derecha, solo la última expresión se usará como resultado a ''while'' condicional. Esto evita el manejo de ''goto''s'' para mantener un bloque único de comandos para ejecutar antes de la verificación de condición.
EDITAR: Esto evita también una llamada a una función de manejo que podría ocuparse de toda la lógica en los operandos izquierdos y, por lo tanto, devolver el resultado lógico. Recuerde que no teníamos una función en línea en el pasado de C. Por lo tanto, esto podría evitar una sobrecarga de llamadas.
i = (i, ++i, 1) + 1;
Analicémoslo paso a paso.
(i, // is evaluated but ignored, there are other expressions after comma
++i, // i is updated but the resulting value is ignored too
1) // this value is finally used
+ 1 // 1 is added to the previous value 1
Entonces obtenemos 2. Y la asignación final ahora:
i = 2;
Lo que sea que haya en yo antes se sobrescribe ahora.