int x, y;
int main() {
x++ + ++y;
x+++ ++y;
x++ +++y;
x +++++ y;
}
Почему эта программа не выдаёт ошибок для 1 и 2 строки, но выдаёт их для 3 и 4?
Первая строка будет разбита на токены следующим образом:
x, ++, +, ++, y, ;.
Что в итоге даст expression statement с валидным выражением (постфиксный инкремент x, префиксный инкремент y и бинарный оператор сложения).
Вторая строка разобьётся на токены аналогично первой строке, потому что preprocessing tokens † вычисляются по принципу maximal munch, а максимальным валидным предварительным токеном будет ++, а не +++.
lex.pptoken#3.3:
If the input stream has been parsed into preprocessing tokens up to a given character:
Третья строка будет разбита на токены следующим образом:
x, ++, ++, +, y, ;.
Отличие от первой и второй строки потому, что после 3 базового символа + нет white space, который в предыдущих случаях разделял предварительные токены + и ++.
В итоге получаем expression statement с невалидным выражением, т.к. к результату постфиксного инкремента применяется постфиксный инкремент.
expr.post.incr#1:
... The operand shall be a modifiable lvalue. ... The result is a prvalue. ...
Четвёртая строка разобьётся на токены аналогично третьей строке, потому что:
white space после x и перед y не влияет на вычисление предварительных токенов;white space после 2 базового символа + не влияет на вычисление предварительных токенов аналогично 1 и 2 строкам.† Подробнее о фазах трансляции можно почитать тут. Тогда станет понятно, зачем разделять предварительные и обычные токены.
error: lvalue required as increment operand
x++ +++y;
^
error: lvalue required as increment operand
x +++++ y;
^
Перевод : прибавление единицы возможно только к адресуемой переменной, а не временному числу.
Примеры НЕ lvalue значений и ошибок :
++ ( 2 + 2 ) ;
int f ( int ) ;
++ f ( 1 ) ;
Первые примеры разбираются компилятором с помощью приоритета операций. Инкремент ++ имеет очень высокий приоритет и вычисляются так:
x++ + ++y; => (x++) + (++y);
x+++ ++y; => (x++)+ (++y);
Ошибочные так :
x++ +++y; => (x++) (++(+y));
x +++++ y; => (x ++)(++(+ y));
где +y или -y это уже не lvalue значение.
Возвращаемое значение у постфиксного и у префиксного оператора тоже разное. ++y возвращает lvalue, а y++ - rvalue. Поэтому:
++(++y) - OK
++(y++) - error
Сборка персонального компьютера от Artline: умный выбор для современных пользователей