Каков результат я == (i = 2)?
Выполните следующий код:
// In Java, output #####
public static void main(String[] args) {
int i = 1;
if(i == (i = 2)) {
System.out.println("@@@@@");
} else {
System.out.println("#####");
}
}
Но:
// In C, output @@@@@,I did test on Clion(GCC 7.3) and Visual Studio 2017
int main(int argc, char *argv[]) {
int i = 1;
if(i == (i = 2)) {
printf("@@@@@");
} else {
printf("#####");
}
return 0;
}
Мотивация для этого вопроса исходит из следующего кода:
// The code is from the JDK 11 - java.util.concurrent.atomic.AtomicInteger
// I am curious about the behavior of the variable prev.
public final int getAndUpdate(IntUnaryOperator updateFunction) {
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.applyAsInt(prev);
if (weakCompareAndSetVolatile(prev, next))
return prev;
haveNext = (prev == (prev = get()));
}
}
Итак, как объяснить вышеупомянутые два разных режима выполнения?
Ответы
Ответ 1
Поведение программы C, выполняющей выражение i == (i = 2)
не определено.
Он исходит из C11 6.5p22:
- Если побочный эффект скалярного объекта не зависит от другого побочного эффекта для одного и того же скалярного объекта или вычисления значения с использованием значения одного и того же скалярного объекта, поведение не определено. Если имеется несколько допустимых порядков подвыражений выражения, поведение не определено, если такой необратимый побочный эффект возникает в любом из заказов.84)
i
в левой части ==
- вычисление значения для значения скалярного объекта i
а правая часть i = 2
имеет побочный эффект присвоения значения 2
i
. LHS и RHS of ==
зависят друг от друга. Следовательно, вся программа не имеет смысла в C.
Компиляция с gcc -Wall
и GCC gcc -Wall
:
unsequenced.c:5:16: warning: operation on ‘i may be undefined [-Wsequence-point]
if(i == (i = 2)) {
~~~^~~~
В отличие от C, Java гарантирует порядок оценки для операндов (слева направо), поэтому
haveNext = (prev == (prev = get()));
корректно в Java. Значение LHS определяется строго до оценки побочного эффекта на RHS.
В C вы должны написать это как что-то вроде
newPrev = get();
haveNext = (prev == newPrev);
prev = newPrev;
Ответ 2
Спецификация языка Java (§15.7) гласит:
Язык программирования Java гарантирует, что операнды операторов, по-видимому, оцениваются в определенном порядке оценки, а именно слева направо.
В спецификации (§15.21.1) также указывается, что:
Значение, созданное оператором ==
true
если значение левого операнда равно значению правого операнда; в противном случае результат будет false
.
Поэтому в Java if-statement во время выполнения будет выглядеть следующим образом, которое, очевидно, оценивается как false
:
if (1 == 2) {
}
В C он просто не определен (см. Ответ Antti).
Ответ 3
В C поведение i == (i = 2)
не определено, поскольку оно пытается как обновить объект, так и использовать значение этих объектов при вычислении без промежуточной точки последовательности. Результат будет зависеть от компилятора, настроек компилятора, даже от окружающего кода.
Ответ 4
Результатом является неопределенное поведение. Если использование этой идиомы может иметь какой-либо эффект; он может работать так, как вы ожидаете, или может стереть ваш жесткий диск или сбой вашей машины. Более того, автор компилятора не обязан предупреждать вас о неопределенном поведении.
Вы должны иметь в виду, что мы не хотим делать неопределенное поведение. Поэтому нам нужно задать себе несколько вопросов.
Каковы некоторые из факторов, которые заставляют комитет по разработке языков оставлять определенные языковые идиомы как неопределенные или определенные поведением поведения?
Первый главный фактор: существуют ли две существующие версии языка на рынке, которые не согласны с поведением конкретной программы?
Следующий важный фактор: обладает ли эта функция естественным образом различными вариантами реализации, некоторые из которых явно лучше других?
Третий фактор: является ли такая сложная функция, что подробное разбиение ее точного поведения было бы трудным или дорогостоящим?
Четвертым фактором является то, что эта функция накладывает большую нагрузку на компилятор для анализа?
Пятый фактор: действительно ли функция налагает большую нагрузку на среду выполнения?
Шестой фактор: действительно ли определение поведения исключает некоторую значительную оптимизацию?
Ответ 5
if(i == (i = 2))
в java-языке результатом следующего оператора будет 1, а в c Language результат будет равен 2, а другой раздел будет запущен. разница в java сначала условие будет проверено, и после этого значение я изменится, но вначале значение изменится, и после этого условия будут проверены и из-за исполнительных оценок на языке Java