Подтвердить что ты не робот

Если скобка имеет более высокий приоритет, то почему оператор инкремента сначала решается?

У меня есть один код строки,

int a = 10;
a = ++a * ( ++a + 5);

Мой ожидаемый результат был 12 * (11 + 5) = 192, но я получил 187. Насколько я знал, что оператор инкремента внутри () должен быть решен первым, то почему первая проблема сначала решена?

4b9b3361

Ответ 1

Выражения оцениваются слева направо. Скобки (и приоритет) просто выражают группировку, они не выражают порядок оценки.

Итак,

 11 * (12 + 5)
++a   ++a

равно

187

Ответ 2

Цитата из Блог Эрика Липперта:

Оценка арифметического выражения контролируется тремя наборами правил: правилами приоритета, правилами ассоциативности и правилами порядка.

Приоритет правила описывают, как должно быть заключено нижнее сжатое выражение, когда выражение смешивает различные типы операторов.

Правила

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

Правила оценки описывают порядок, в котором оценивается каждый операнд в выражении.

Более высокий приоритет приводит к группировке операндов с оператором и не означает оценку операндов. Это порядок оценки, который определяет последовательность оценки подвыражений в выражении.


Обновление:

Как я вижу, многие программисты считают, что утверждение

a = ++a * ( ++a + 5);  

вызывается поведение undefined. Да, он будет вызывать UB, если нет гарантии порядка оценки операндов оператора.

Но это не так в контексте языка Java-программирования. Он имеет четко определенное поведение в java (а также в С#). Спецификация языка Java гласит, что:

15.7. Порядок оценки

Язык программирования Java гарантирует, что операнды операторов выглядят оцениваются в определенном порядке оценки, а именно слева направо.

Пример 15.7.1-1. Сначала оценивается левый Операнд

В следующей программе оператор * имеет левый операнд, который содержит назначение переменной и правый операнд, содержащий ссылку на ту же переменную. Значение, созданное ссылкой, будет отражать тот факт, что назначение произошло первым.

class Test1 {
    public static void main(String[] args) {
        int i = 2;
        int j = (i=3) * i;
        System.out.println(j);
    }
}

Эта программа производит вывод:

9

Недопустимо для вычисления оператора * производить 6 вместо 9.

Но, по-прежнему java-спецификация четко заявляет, что не писать такие коды:

Рекомендуется, чтобы код не полагался на эту спецификацию. Код обычно более ясен, когда каждое выражение содержит не более одного побочного эффекта, как его внешнюю операцию, и когда код не зависит от того, какое именно исключение возникает в результате оценки выражений слева направо.

Ответ 3

Из этого фрагмента

int a = 10;
a = ++a * ( ++a + 5);

Иногда самым простым решением является использование javap для понимания порядка оценки:

 0: bipush 10 // push 10 onto the stack (stack={10})
 2: istore_1  // store 10 into variable 1 (a = 10, stack={})
 3: iinc 1, 1 // increment local variable 1 by 1 (a = 11, stack={})
 6: iload_1   // push integer in local variable 1 onto the stack (a = 11, stack = {11})
 7: iinc 1, 1 // increment local variable 1 by 1 (a = 12, stack={11})
 10: iload_1  // push integer in local variable 1 onto the stack (a = 12, stack = {12, 11})
 11: iconst_5 // load the int value 5 onto the stack (a = 12, stack = {5, 12, 11})
 12: iadd     // add 5 and 12 (a = 12, stack = {17, 11})
 13: imul     // multiply 17 and 11 (a = 12, stack = {})
  • a увеличивается на 1. (строка 3)//a = 11
  • a увеличивается на 1. (строка 7)//a = 12
  • добавить 5 в a (строка 12)//a = 17
  • умножьте 11 на 17 (строка 13)//a = 187

(10 + 1 + 1 + 5) * 11 = 187

Ответ 4

Эффект скобок заключается в том, чтобы контролировать, какие вычисленные значения используются в качестве операндов для последующих операций. Они контролируют последовательность, в которой операции выполняются только в той степени, в которой операция не может быть оценена до тех пор, пока не будут выполнены ее операнды. Рассмотрим выражения:

(a()+b()) * (c()+d())
a() + (b()*c()) + d()

Скобки не должны (и в Java не могут) влиять на порядок, в котором вызываются вызовы a(), b(), c() и d(). Они могут повлиять на то, выполняется ли умножение до или после вызова d(), но только в очень редких случаях (например, d() вызывает интерфейс Java Native, который изменяет режим численного округления, используемый в умножении, способом, которым Java не знает about) будет иметь какой-либо способ узнать или заботиться о том, выполнялось ли умножение до или после d().

В противном случае важно то, что в первом случае одна операция сложения будет действовать на() и b(), а другая - на c() и d(); умножение будет действовать на() + b() и c() + d(). В другом случае первое умножение будет действовать на b() и c(), первое сложение на a() и вышеупомянутое произведение, а второе добавление на первую сумму и d().

Ответ 5

  int a = 10;
  a = ++a * ( ++a + 5);

выше типы выражений всегда оцениваются слева направо, будь то C или JAVA

в этом случае он так решается 11 * (12 + 5), что приводит к 11 * 17 = 187//w.r.t java

но если он решает одно и то же выражение w.r.t C-language

тогда ответ изменяется как способ изменения оценки

в c происходит первый предварительный приращение/пре-декремент, поэтому, если "N" нет времени pre inc/dec есть ли в выражении, тогда inc/dec произойдет сначала "N" no times

то одно и то же значение будет заменено в каждом вступлении переменной в выражении и вычисляется значение выражения и после этого происходит приращение/декремент post

i. a получает приращение до 11, затем снова 12, поскольку в выражении есть два приращения для a, а затем выражение оценивается как

12 * (12 + 5) = 12 * 17 = 204//w.r.t C-language