Pourquoi «++ i ++» n'est-il pas valide alors que (++ i) ++ est valide?

14

Prenons le code suivant:

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

Il se compile avec ce qui suit avec une erreur:

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

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

    3 |     int b = ++i++;

      |                ^~

Cela me semble juste. L'incrément de suffixe a une priorité plus élevée que l'incrément de préfixe, donc le code est analysé comme int b = ++(i++);et iest une valeur r. D'où l'erreur.

Considérons maintenant cette variante entre parenthèses pour remplacer les priorités par défaut:

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

Ce code compile et renvoie 3. À lui seul, cela me semble juste, mais il semble en contradiction avec le premier code.

La question: pourquoi (++i)un lvaluequand ine l'est pas?

Merci!

MISE À JOUR: le message d'erreur ci-dessus provenait de gcc (x86-64 9.2). Voici le rendu exact: erreur avec gcc

Clang x86-64 9.0.0 a un message assez différent: erreur avec clang

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

    int b = ++i++;

            ^ ~~~

Avec GCC, vous avez l'impression que le problème est avec l'opérateur postfix et vous pouvez alors vous demander pourquoi ++iest OK alors que ce in'est pas le cas, d'où ma question. Avec Clang, il est plus clair que le problème vient de l'opérateur de préfixe.

Bktero
la source
C'était à l'origine tagué avec C, ce n'est certainement pas valide C.
Antti Haapala
En effet désolé! J'ai supposé que le comportement était le même en C ...
Bktero

Réponses:

23

iet ++isont tous les deux lvalues, mais i++est une rvalue.

++(i++)ne peut pas être valide, car le préfixe ++est appliqué à i++, qui est une valeur r. Mais (++i)++c'est bien parce que ++ic'est une valeur.

Notez qu'en C, la situation est différente; i++et ++isont tous les deux des valeurs. (C'est un exemple de la raison pour laquelle les gens devraient cesser de supposer que C et C ++ ont les mêmes règles. Les gens insèrent ces hypothèses dans leurs questions, qui doivent ensuite être réfutées.)

Brian
la source
4

Cette déclaration

int b = ++i++;

est équivalent à

int b = ++( i++ );

L'opérateur d'incrémentation postfixe renvoie la valeur de l'opérande avant l'incrémentation.

De la norme C ++ 17 (8.2.6 Incrémentation et décrémentation)

1 La valeur d'une expression postfix ++ est la valeur de son opérande ... Le résultat est une valeur .

Tandis que l'opérateur d'incrément unaire renvoie lvalue après son incrément. Donc, cette déclaration

int b = (++i)++;

est valable. Vous pourriez par exemple écrire

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

De la norme C ++ 17 (8.3.2 Incrémentation et décrémentation)

1 L'opérande de préfixe ++ est modifié en ajoutant 1. L'opérande doit être une valeur l modifiable. Le type de l'opérande doit être un type arithmétique autre que cv bool ou un pointeur vers un type d'objet complètement défini. Le résultat est l'opérande mis à jour; c'est une valeur l , et c'est un champ binaire si l'opérande est un champ binaire ....

Faites attention qu'en C, les deux opérateurs retournent une valeur au lieu de lvalue. Donc en C cette déclaration

int b = (++i)++;

est invalide.

Vlad de Moscou
la source
3

donc le code est analysé comme int b = ++ (i ++); et i est une valeur r.

Non in'est pas une valeur. iest une valeur l. i++est une rvalue (prvalue pour être spécifique).

eerorika
la source