Dlaczego „++ i ++” jest niepoprawny, podczas gdy (++ i) ++ jest ważny?

14

Rozważmy następujący kod:

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

Kompiluje się z następującymi błędami:

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

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

    3 |     int b = ++i++;

      |                ^~

Brzmi dla mnie uczciwie. Przyrost Postfiksa ma wyższy priorytet niż Przyrost Prefiksu , więc kod jest analizowany jako int b = ++(i++);i ijest wartością rvalue. Stąd błąd.

Rozważmy teraz ten wariant z nawiasami, aby zastąpić domyślne priorytety:

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

Ten kod kompiluje się i zwraca 3. Samo w sobie brzmi to uczciwie, ale wydaje się być sprzeczne z pierwszym kodem.

Powstaje pytanie: dlaczego (++i)to lvalue, kiedy inie jest?

Dzięki!

AKTUALIZACJA: powyższy komunikat o błędzie pochodzi z gcc (x86-64 9.2). Oto dokładne renderowanie: błąd z gcc

Clang x86-64 9.0.0 ma zupełnie inny komunikat: błąd z clang

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

    int b = ++i++;

            ^ ~~~

Dzięki GCC masz wrażenie, że problem dotyczy operatora Postfiksa, a następnie możesz wędrować, dlaczego ++ijest OK, a inie jest, stąd moje pytanie. W przypadku Clanga jest wyraźniejsze, że problem dotyczy operatora prefiksu.

Bktero
źródło
Pierwotnie oznaczono to literą C, z pewnością nie jest poprawne C.
Antti Haapala
Rzeczywiście przepraszam! Zakładałem, że zachowanie było takie samo w C ...
Bktero,

Odpowiedzi:

23

ii ++ioba są wartościami, alei++ są wartością.

++(i++)nie może być ważny, jako przedrostek ++jest stosowany do i++, który jest rvalue. Ale (++i)++jest w porządku, ponieważ++i jest wartością.

Zauważ, że w C sytuacja jest inna; i++i ++ioba są wartościami. (Jest to przykład tego, dlaczego ludzie powinni przestać zakładać, że C i C ++ mają te same reguły. Ludzie umieszczają te założenia w swoich pytaniach, które należy następnie obalić.)

Brian
źródło
4

Ta deklaracja

int b = ++i++;

jest równa

int b = ++( i++ );

Operator przyrostka Postfiks zwraca wartość argumentu przed przyrostem.

Ze standardu C ++ 17 (8.2.6 Zwiększanie i zmniejszanie)

1 Wartość wyrażenia postfix ++ jest wartością jego operandu ... Wynikiem jest prvalue .

Podczas gdy operator jednostkowej inkrementacji zwraca wartość po jej inkrementacji. Więc ta deklaracja

int b = (++i)++;

jest ważny. Możesz na przykład pisać

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

Ze standardu C ++ 17 (8.3.2 Zwiększanie i zmniejszanie)

1 Argument prefiksu ++ jest modyfikowany przez dodanie 1. Operandem jest modyfikowalna wartość. Operand powinien być typem arytmetycznym innym niż cv bool lub wskaźnikiem do całkowicie zdefiniowanego typu obiektu. Wynikiem jest zaktualizowany operand; to jest wartość i jest to pole bitowe, jeśli operand jest polem bitowym ...

Zwróć uwagę, że w C oba operatory zwracają wartość zamiast wartości. Więc w C ta deklaracja

int b = (++i)++;

jest nieważny.

Vlad z Moskwy
źródło
3

więc kod jest analizowany jako int b = ++ (i ++); a ja to wartość.

Nie. iTo nie jest wartość. ijest wartością. i++jest wartością (prvalue, aby być konkretnym).

eerorika
źródło