Разный порядок операторов

166
03 мая 2019, 00:50
int x, y;
int main() {
    x++ + ++y;
    x+++  ++y;
    x++  +++y;
    x +++++ y;
}

Почему эта программа не выдаёт ошибок для 1 и 2 строки, но выдаёт их для 3 и 4?

Answer 1

Первая строка будет разбита на токены следующим образом:

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:

  • ...
  • ...
  • Otherwise, the next preprocessing token is the longest sequence of characters that could constitute a preprocessing token, even if that would cause further lexical analysis to fail, except that a header-name is only formed within a #include directive.

Третья строка будет разбита на токены следующим образом:

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 строкам.

† Подробнее о фазах трансляции можно почитать тут. Тогда станет понятно, зачем разделять предварительные и обычные токены.

Answer 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
READ ALSO
Отправка сообщений websocket

Отправка сообщений websocket

Пишу веб сокет сервер на языке javaЕсть ксласс с обработчиком событий: открытие, закрытие соединения, ошибки, и сообщения

167
Servlet java web.xml

Servlet java web.xml

Создал сервлет, имею файл webxml

193
Повторная инициализация cryptoki сетевого HSM

Повторная инициализация cryptoki сетевого HSM

Столкнулся с проблемой повторной инициализации библиотекипри первом вызове все отрабатывает отлично, но после истечения некоторого времени...

168
@value( ${} ) в spring не работает

@value( ${} ) в spring не работает

Пишу приложение на java с использованием SpringНужно передать значение ключа из файла app

158