¿Por qué "++ i ++" no es válido mientras que (++ i) ++ es válido?

14

Consideremos el siguiente código:

int main() {
    int i = 2;
    int b = ++i++;
    return 3;
}

Se compila con lo siguiente con un error:

<source>: In function 'int main()':

<source>:3:16: error: lvalue required as increment operand

    3 |     int b = ++i++;

      |                ^~

Esto me parece justo. El incremento de postfix tiene mayor prioridad que el incremento de prefijo, por lo que el código se analiza int b = ++(i++);y ies un valor r. De ahí el error.

Consideremos ahora esta variante con paréntesis para anular las prioridades predeterminadas:

int main() {
    int i = 2;
    int b = (++i)++;
    return 3;
}

Este código compila y devuelve 3. Por sí solo, esto me parece justo, pero parece estar en contradicción con el primer código.

La pregunta: ¿por qué (++i)es un lvaluecuándo ino?

¡Gracias!

ACTUALIZACIÓN: el mensaje de error que se muestra arriba era de gcc (x86-64 9.2). Aquí está la representación exacta: error con gcc

Clang x86-64 9.0.0 tiene un mensaje bastante diferente: error con clang

<source>:3:13: error: expression is not assignable

    int b = ++i++;

            ^ ~~~

Con GCC, tiene la impresión de que el problema está en el operador de postfix y luego puede deambular por qué ++iestá bien y ino, de ahí mi pregunta. Con Clang es más claro que el problema está en el operador de prefijo.

Bktero
fuente
Esto fue originalmente etiquetado con C, ciertamente no es válido C.
Antti Haapala
De hecho lo siento! Supuse que el comportamiento era el mismo en C ...
Bktero

Respuestas:

23

iy ++ison ambos valores, pero i++es un valor.

++(i++)no puede ser válido, ya que ++se está aplicando el prefijo i++, que es un valor r. Pero (++i)++está bien porque ++ies un valor.

Tenga en cuenta que en C, la situación es diferente; i++y ++ison ambos valores. (Este es un ejemplo de por qué las personas deberían dejar de asumir que C y C ++ tienen las mismas reglas. Las personas insertan estos supuestos en sus preguntas, que luego deben ser refutadas).

Brian
fuente
4

Esta declaración

int b = ++i++;

es equivalente a

int b = ++( i++ );

El operador de incremento de postfix devuelve el valor del operando antes del incremento.

Del estándar C ++ 17 (8.2.6 Incremento y disminución)

1 El valor de una expresión postfix ++ es el valor de su operando ... El resultado es un prvalue .

Mientras que el operador de incremento unario devuelve lvalue después de su incremento. Entonces esta declaración

int b = (++i)++;

es válida. Podrías por ejemplo escribir

int b = (++++++++i)++;

Del estándar C ++ 17 (8.3.2 Incremento y decremento)

1 El operando del prefijo ++ se modifica agregando 1. El operando será un valor l modificable. El tipo del operando será un tipo aritmético distinto de cv bool, o un puntero a un tipo de objeto completamente definido. El resultado es el operando actualizado; es un valor de l , y es un campo de bits si el operando es un campo de bits ...

Tenga en cuenta que en C los dos operadores devuelven un valor en lugar de lvalue. Entonces en C esta declaración

int b = (++i)++;

es inválido.

Vlad de Moscú
fuente
3

entonces el código se analiza como int b = ++ (i ++); y yo soy un valor

No. ino es un valor. ies un valor i++es un rvalue (prvalue para ser específico).

eerorika
fuente