Путаница по поводу приоритета операторов в C ++ - PullRequest
0 голосов
/ 06 декабря 2018

Скажем, в следующем тестовом выражении:

int ggg9 = fggg2() + (fggg3() && fggg4() < fggg5() * fggg6());
//                 4          11         6         3

если мы будем следовать приоритету оператора (показан в строке с комментариями под выражением), я бы предположил, что выражение всначала будут оцениваться парены, а затем результат будет добавлен к fggg2().

. Таким образом, я предполагаю, что он будет решен в следующем порядке:

int r1 = fggg5() * fggg6(); //Precedence 3 (inside parens)
int r2 = fggg4() < r1;      //Precedence 6 (inside parens)
int r3 = fggg3() && r2;     //Precedence 11 (inside parens)
int ggg9 = fggg2() + r3;    //Outside of parens, so it's last

Но x86-64 gcc 8.2 разрешает это как таковое:

enter image description here

(я преобразую его обратно в C ++)

    int i0;
    int r2 = fggg2();
    int r3 = fggg3();
    if(!r3) goto L13;
    int r4 = fggg4();
    int r5 = fggg5();
    int r6 = fggg6();
    int i1 = r5 * r6;
    if(r4 >= i1) goto L13
    i0 = 1;
    goto L14
L13:
    i0 = 0;
L14:
    int ggg9 = i0 + r2;

Так почему же оператор && оценивается до *, а затем <, когда их приоритет равен 11, 3, 6, соответственно?

Наконец, почему это не так?заботиться о паренах, оценивая сначала fggg2()VS2017, похоже, оценивает его в последний раз.

Из того, что я вижу, компилятор gcc просто оценивал все эти функции слева направо, безотносительно к приоритету.

Ответы [ 3 ]

0 голосов
/ 06 декабря 2018

Вы путаете приоритет с порядком оценки .

Это довольно распространенная путаница.Возможно, потому что слово «предшествовать» в английском может иметь временную коннотацию.Но на самом деле это означает иерархию ранжирования (например, здесь ).

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

Функции a,b,c могут все еще вызываться в любом порядке.

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

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

Левый операнд + может оцениваться перед правым операндом +, даже если правый операнд состоит из множества подвыражений.Компилятор может оценить все «листовые» операнды, сохранить результаты в стеке, а затем выполнить вычисления значений.

Также не обязательно существует строгий порядок вычислений значений, например, в w() * x() + y() * z(), два вычисления значений * могут выполняться в любом порядке.


В вашем кодеоператор && имеет специальное ограничение порядка (иногда называемое короткое замыкание ).Левый операнд должен быть оценен до начала вычисления правого операнда.

Приоритет говорит нам, что левый операнд && равен fgg3(), а правый операнд && это fggg4() < fggg5() * fggg6()).Поэтому требуется, чтобы fgg3() вызывался перед любым из fgg4, fgg5 и fgg6.Других ограничений на порядок вычисления операндов в вашем примере нет.fgg2 может произойти в любое время, а 4, 5, 6 могут быть в любом порядке, если они все после 3.

0 голосов
/ 06 декабря 2018

Вы забыли учесть оценку короткого замыкания оператора &&.

Левая часть оператора && всегда оценивается перед правой стороной.

В вашей попытке упростить операцию, первая половина r3 должна быть оценена, если она оценивается как ложная, ни одно из того, что вы называете r1 и r2, не будет оценено.

Оценка короткого замыкания требуется в C ++.

0 голосов
/ 06 декабря 2018

Вы путаете порядок вычисления с приоритетом операторов, в то время как приоритет гарантированно сохраняется, порядок оценки - нет, компилятор может выбирать порядок.

Может оценивать fggg2() сначала, посередине или между оценками других операндов.

...