Поведение оператора до и после приращения в 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), которая обеспечивает согласованность, но я не обладаю большими знаниями здесь.