Поведение оператора до и после приращения в C, C++, Java и C#

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Это не реальный пример. Это просто теоретический вопрос о том, как работают эти языки.

Какие именно различия между C/C++, C# и Java, когда дело доходит до операторов post & pre инкремент?

Это то, что я получаю с VC++10, Java 1.6 и C# 4

int a = 2;
int b = a++ + a++;
int c = ++a + a++ + a++;

      +-----+------+------+----+
      |  C  | C++  | Java | C# |
+-----+-----+------+------+----+
| a   |  7  |  7   |   7  |  7 |
+-----+-----+------+------+----+
| b   |  4  |  4   |   5  | 5  |
+-----+-----+------+------+----+
| c   | 15  |  15  |  16  | 16 |
+-----+-----+------+------+----+

6 ответов

Решение

Java и C# оценивают выражения слева направо, и побочные эффекты видны сразу.

В C++ порядок вычисления подвыражений не определен, и модификация одного и того же объекта дважды без промежуточной точки последовательности является неопределенным поведением.

У меня нет времени, чтобы написать подробное описание различий между C++, C, C# и Java. Я просто скажу, что поведение C# операторов до и после инкремента полностью определено (в однопоточных сценариях; если вы хотите узнать об его атомарности, гарантии относительно наблюдений за порядками чтения и записи в многопроцессорных моделях со слабой памятью и и так далее, вы сами проводите это исследование.) Это не полностью определено в C и C++; у компилятора есть широкие возможности делать все что угодно с изменением порядка побочных эффектов. Я никогда не использовал Java, поэтому я не собираюсь рисковать предположением относительно того, что делает Java.

Для получения дополнительной информации о том, что C# делает, вы должны прочитать спецификацию C#. Для краткого ознакомления с этим прочитайте мой ответ на этот вопрос:

В чем разница между i++ и ++i?

Для еще более короткого приема:

Субэкспрессии в выражении C# логически группируются по приоритету и ассоциативности, а затем оцениваются слева направо независимо. (Так, например, A() + B() * C() оценивает A(), затем B(), затем C(). Тот факт, что умножение "предшествует" сложению не имеет значения; подвыражения всегда вычисляются) слева направо.)

Если оценка подвыражения вызывает побочный эффект из-за подвыражения до или после приращения, то побочный эффект происходит непосредственно перед созданием результата.

В C++ это неопределенное поведение, поэтому любой ответ будет правильным. Посмотрите Неопределенное поведение и точки последовательности для получения дополнительной информации.

Не уверен насчет других языков, но я ожидаю, что этот код там тоже будет неправильным.

РЕДАКТИРОВАТЬ:
Смотрите ответ Эрика Липперта о C#. Он опровергает мое предположение о поведении C#.

В C++ по крайней мере это неопределенное поведение. Цитируя стандарт C++:

Между предыдущей и следующей точкой последовательности скалярному объекту должно быть изменено его сохраненное значение не более одного раза путем оценки выражения.

Мне нравится этот вопрос, и я нашел очень хорошие объяснения, но я просто хочу объяснить этот вопрос по значению, как он оценивается:

Я буду говорить только о Java и C/C++, так как я не знаю о C#

Заявления оцениваются следующими способами

В яве

Утверждение |||||||||||||||||||||||||||||||||||||||||||||| |||||| след

int a= 2;                     a=2
int b= a++ + a++;             a=2, a=3

here value of a=4

int c = ++a + a++ + a++;      a=5, a=5, a=6

here value of a=7

В C/C++

Трассировка заявления

int a= 2;                     a=2
int b= a++ + a++;             a=2, a=2

here value of a=4

int c = ++a + a++ + a++;      a=5, a=5, a=5

here value of a=7

Короче говоря, в java выражение идет слева направо, поэтому при 2-ой букве "a" оно извлекает новое значение, а в c / C++ сначала вычисляет целое выражение, а затем увеличивает все операнды оператора.

Модель памяти Java обеспечивает порядок выполнения загрузки и сохранения, поэтому она должна получаться одинаковой на любой JVM (я полагаю).

Похоже, что C++ имеет тот же порядок операций, но как только вы используете его дважды в строке, вы начинаете сталкиваться с другими вещами (Влад прямо здесь). Если вы попробуете другие компиляторы C++, вы можете обнаружить, что они предлагают разные ответы.

Я уверен, что C# имеет тот же порядок операций, но я предполагаю, что у них есть модель памяти (например, Java), которая обеспечивает согласованность, но я не обладаю большими знаниями здесь.

Другие вопросы по тегам