Por que "++ i ++" é inválido enquanto (++ i) ++ é válido?

14

Vamos considerar o seguinte código:

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

Ele é compilado com o seguinte com um erro:

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

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

    3 |     int b = ++i++;

      |                ^~

Isso parece justo para mim. O incremento do Postfix tem prioridade mais alta que o incremento do prefixo, portanto, o código é analisado como int b = ++(i++);e ié um rvalue. Daí o erro.

Vamos agora considerar esta variante entre parênteses para substituir as prioridades padrão:

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

Esse código compila e retorna 3. Por si só, isso me parece justo, mas parece contraditório com o primeiro código.

A pergunta: por que (++i)um lvaluequando inão é?

Obrigado!

UPDATE: a mensagem de erro mostrada acima era do gcc (x86-64 9.2). Aqui está a renderização exata: error with gcc

Clang x86-64 9.0.0 tem uma mensagem bem diferente: erro com clang

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

    int b = ++i++;

            ^ ~~~

Com o GCC, você tem a impressão de que o problema está no operador postfix e, em seguida, pode perambular por que ++iestá tudo bem enquanto inão estiver, daí a minha pergunta. Com o Clang, fica mais claro que o problema está no operador de prefixo.

Bktero
fonte
Esta foi originalmente marcado com C, que certamente não é válido C.
Antti Haapala
Desculpe mesmo! Eu assumi o comportamento foi o mesmo em C ...
Bktero

Respostas:

23

ie ++isão ambos lvalues, mas i++é um rvalue.

++(i++)não pode ser válido, pois o prefixo ++está sendo aplicado i++, que é um rvalue. Mas (++i)++está bem porque ++ié um valor l.

Observe que em C, a situação é diferente; i++e ++isão ambos os valores. (Este é um exemplo de por que as pessoas devem parar de supor que C e C ++ têm as mesmas regras. As pessoas inserem essas suposições em suas perguntas, que devem ser refutadas.)

Brian
fonte
4

Esta declaração

int b = ++i++;

é equivalente a

int b = ++( i++ );

O operador de incremento postfix retorna o valor do operando antes do incremento.

Do padrão C ++ 17 (8.2.6 Incremento e decremento)

1 O valor de uma expressão postfix ++ é o valor de seu operando ... O resultado é um pré-valor .

Enquanto o operador de incremento unário retorna lvalue após seu incremento. Então esta declaração

int b = (++i)++;

é válido. Você poderia, por exemplo, escrever

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

Do padrão C ++ 17 (8.3.2 Incremento e decremento)

1 O operando do prefixo ++ é modificado adicionando 1. O operando deve ser um lvalue modificável. O tipo do operando deve ser um tipo aritmético que não seja cv bool ou um ponteiro para um tipo de objeto completamente definido. O resultado é o operando atualizado; é um lvalue e é um campo de bits se o operando for um campo de bits ....

Preste atenção que em C os dois operadores retornam um valor em vez de lvalue. Então em C esta declaração

int b = (++i)++;

é inválido.

Vlad de Moscou
fonte
3

portanto, o código é analisado como int b = ++ (i ++); e i é um rvalor.

No. inão é um rvalue. ié um valor l. i++é um rvalue (prvalue para ser específico).

eerorika
fonte