En C y C++, ¿una expresión que usa el operador de coma como “a=b,++ a;” no está definida?
undefined-behavior (2)
Toma estos tres fragmentos de código C:
1) a = b + a++
2) a = b + a; a++
3) a = b + a, a++
Todo el mundo sabe que el ejemplo 1 es una cosa muy mala e invoca claramente un comportamiento indefinido. El ejemplo 2 no tiene problemas. Mi pregunta es con respecto al ejemplo 3. ¿El operador de coma funciona como un punto y coma en este tipo de expresión? ¿2 y 3 son equivalentes o 3 es tan indefinido como 1?
Específicamente estaba considerando esto con respecto a algo como free(foo), foo = bar
. Este es básicamente el mismo problema que el anterior. ¿Puedo estar seguro de que foo se libera antes de ser reasignado, o es un problema de secuencia clara?
Soy consciente de que ambos ejemplos son en gran medida inútiles y tiene mucho más sentido simplemente usar un punto y coma y terminar con él. Solo pregunto por curiosidad.
El caso 3 está bien definido.
La sección 6.5.17 de la norma C con respecto al operador de coma ,
dice lo siguiente:
2 El operando izquierdo de un operador de coma se evalúa como una expresión de vacío; 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.
La sección 5.14 p1 del estándar C ++ 11 tiene un lenguaje similar:
Un par de expresiones separadas por una coma se evalúa de izquierda a derecha; La expresión de la izquierda es una expresión de valor descartado. Cada cálculo de valor y efecto secundario asociado con la expresión izquierda se secuencia antes de cada cálculo de valor y efecto secundario asociado con la expresión derecha. El tipo y el valor del resultado son el tipo y el valor del operando correcto; el resultado es de la misma categoría de valor que su operando derecho, y es un campo de bits si su operando derecho es un glvalue y un campo de bits.
Debido al punto de secuencia, a = b + a
se garantiza que se evaluará completamente antes de a++
en la expresión a = b + a, a++
.
Con respecto a free(foo), foo = bar
, esto también garantiza que foo
se libere antes de asignar un nuevo valor.
a = b + a, a++;
está bien definido, pero a = (b + a, a++);
puede ser indefinido.
En primer lugar, la precedencia del operador hace que la expresión sea equivalente a (a = (b+a)), a++;
, donde +
tiene la prioridad más alta, seguido de =
, seguido de,. El operador de coma incluye un punto de secuencia entre la evaluación de su operando izquierdo y derecho. Así que el código es, sin interés, completamente equivalente a:
a = b + a;
a++;
Que por supuesto está bien definido.
Si hubiésemos escrito a = (b + a, a++);
, entonces el punto de secuencia en el operador de coma no salvaría el día. Porque entonces la expresión habría sido equivalente a
(void)(b + a);
a = a++;
- En C y C ++ 14 o más,
a = a++
tiene secuencia, (ver C11 6.5.16 / 3). Lo que significa que este es un comportamiento indefinido (Por C11 6.5 / 2). Tenga en cuenta que C ++ 11 y C ++ 14 estaban mal formulados y eran ambiguos. - En C ++ 17 o posterior, los operandos del operador
=
se secuencian de derecha a izquierda y esto todavía está bien definido.
Todo esto suponiendo que no se produzca una sobrecarga del operador C ++. En ese caso, se evaluarán los parámetros de la función de operador sobrecargado, se realizará un punto de secuencia antes de llamar a la función, y lo que suceda a partir de ahí dependerá de los aspectos internos de esa función.