Después de leer esta respuesta sobre el comportamiento indefinido y los 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.
printf("2\n");
Respuestas:
En la expresión
(i, ++i, 1)
, la coma utilizada es el operador de comaDebido a que descarta su primer operando, generalmente solo es útil cuando el primer operando tiene efectos secundarios deseables . Si el efecto secundario para el primer operando no tiene lugar, entonces el compilador puede generar advertencia sobre la expresión sin efecto.
Entonces, en la expresión anterior,
i
se evaluará el extremo izquierdo y se descartará su valor. Luego++i
será evaluado e incrementarái
en 1 y nuevamente el valor de la expresión++i
será descartado, pero el efecto secundarioi
es permanente . Luego1
será evaluado y el valor de la expresión será1
.Es equivalente a
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.
fuente
i
se inicia con5
. Mira la declaración de la declaraciónint i = 5;
.++i
, esta expresión se evaluará,i
se incrementará y este valor incrementado será el valor de la expresión. En caso dei++
que se evalúe esta expresión, el valor anterior dei
será el valor de la expresión,i
se incrementará en cualquier momento entre el punto de secuencia anterior y el siguiente de la expresión.Citando de
C11
, capítulo6.5.17
, operador de comaEntonces, en tu caso,
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 descartado1
valor devuelto.Entonces, la declaración final parece
y
i
llega a2
. Supongo que esto responde a sus dos preguntas,i
obtiene un valor 2?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.fuente
i
claramente no tiene ningún efecto. Sin embargo, no creo que fuera tan obvio para un tipo que no conoce el operador de coma (y no sabía cómo buscar ayuda, aparte de hacer una pregunta). Lástima que tengo tantos votos negativos! Comprobaré las otras respuestas y luego decidiré cuál aceptar. ¡Gracias! Buena respuesta superior por cierto.Analicémoslo paso a paso.
Entonces obtenemos 2. Y la asignación final ahora:
Lo que sea que haya en yo antes se sobrescribe ahora.
fuente
++i
no contribuye al resultado.int i = 0; for( ;(++i, i<max); )
El resultado de
es
por
la evaluación ocurre de tal manera que el
,
operador descarta el valor evaluado y retendrá el valor más correcto que es1
Entonces
fuente
Encontrarás una buena lectura en la página wiki para el operador de coma .
Básicamente
Esto significa que
a su vez, evaluará
i
, descartará el resultado, evaluarái++
, descartará el resultado y luego evaluará y regresará1
.fuente
(void)exp; a= exp2;
mientras solo necesitabaa = exp, exp2;
)Necesita saber qué está haciendo el operador de coma aquí:
Tu expresión:
La primera expresión,
i
se evalúa, la segunda expresión,++i
se evalúa y la tercera expresión1
, se devuelve para toda la expresión.Así, el resultado es:
i = 1 + 1
.Para su pregunta adicional, como puede ver, la primera expresión
i
no tiene ningún efecto, por lo que el compilador se queja.fuente
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):
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.
fuente