Ассоциативность операторов с «постфиксным декрементом» и «логическими операторами И» в c - PullRequest
0 голосов
/ 10 октября 2018

Отказ от ответственности: я не кодирую, как это, я просто пытаюсь понять, как работает язык c !!!!

Вывод 12.

Это выражение (a-- == 10 && a-- == 9) оценивает слева направо, и a все еще равно 10 при a-- == 10, но a равно 9 для a-- == 9.

1) Есть ли четкое правило относительно того, когда после инкремента оценивать?Из этого примера кажется, что он оценивается до &&, но после ==.Это потому, что логический оператор && делает a-- == 10 полным выражением, поэтому a обновляется после выполнения?

2) Также для c / c ++ некоторые операторы, такие как декремент префикса, выполняются справа налево, поэтому a == --a сначала уменьшает значение a до 9, а затем сравнивает 9 == 9. Есть ли причина, почему c / c ++ разработан таким образом?Я знаю, что для Java все наоборот (оценивается слева направо).

#include <stdio.h>

int main() {
    int a = 10;
    if (a-- == 10 && a-- == 9)
        printf("1");
    a = 10;
    if (a == --a)
        printf("2");
    return 0;
}

Ответы [ 3 ]

0 голосов
/ 10 октября 2018

С «логическим и» оператором (a-- == 10 && a-- == 9) является правильно сформированным выражением (без неопределенного поведения, как в a++ + a++).

Стандарт C говорит о «логических и» / «логических или» операторах:

гарантирует оценку слева направо;после оценки первого операнда существует точка последовательности.

Таким образом, все побочные эффекты первого подвыражения a-- == 10 завершены до второго подвыражения a-- == 9 оценки.a равно 9 до вычисления второго подвыражения.

0 голосов
/ 10 октября 2018

Логический оператор && содержит последовательность между вычислением первого и второго операнда.Частично это связано с тем, что любой побочный эффект (например, выполняемый оператором --) в качестве части левой стороны завершается до оценки правой стороны.

Это подробно описано в разделе 6.5.13p4стандарт C относительно логического оператора AND:

В отличие от побитового двоичного оператора &, оператор && гарантирует оценку слева направо;если вычисляется второй операнд, между оценками первого и второго операндов существует точка последовательности.Если первый операнд сравнивается равным 0, второй операнд не оценивается.

В случае этого выражения:

(a-- == 10 && a-- == 9)

Текущее значение a (10) сначала сравнивается на равенство против 10. Это верно, поэтому правая сторона затем оценивается, но не раньше, чем побочный эффект уменьшения a, который был сделан на левой стороне.Затем текущее значение a (теперь 9) сравнивается на равенство против 9. Это также верно, поэтому все выражение оценивается как true.Перед выполнением следующего оператора выполняется побочный эффект уменьшения на a, который был выполнен с правой стороны.

Однако это выражение:

if (a == --a)

Включает чтение и запись a в том же выражении без точки последовательности.Это вызывает неопределенное поведение .

0 голосов
/ 10 октября 2018

Это выражение (a-- == 10 && a-- == 9) оценивается слева направо,

Да, в основном, но только потому, что &&special.

и a по-прежнему равен 10 в a-- == 10

Да, потому что a-- возвращает старое значение.

но a равно 9 для a-- == 9.

Да, поскольку точка последовательности в && гарантирует, что обновление до значения a завершено до оценки RHS.

1) Существует ли четкое правило относительно оценки после приращения?

На мой взгляд, лучший ответ - «нет».Побочные эффекты из-за ++ и -- завершаются в какой-то момент до следующей точки последовательности, но кроме этого, вы не можете сказать.Для четко определенных выражений не имеет значения, когда побочные эффекты завершены.Если выражение чувствительно к завершению побочного эффекта, это обычно означает, что выражение не определено.

Из этого примера кажется, что оно вычисляется до &&, но после ==.Это потому, что логический оператор && делает a-- == 10 полным выражением, поэтому a обновляется после выполнения?

В основном да.

2) Такжедля c / c ++ некоторые операторы, такие как декремент префикса, выполняются справа налево

Осторожно.Я не уверен, что вы имеете в виду, но что бы это ни было, я почти уверен, что это неправда.

, поэтому a == - сначала уменьшает a до 9, а затем сравнивает 9 ==9.

Нет, a == --a не определено.Нет никаких сведений о том, что он делает.

Есть ли причина, почему C / C ++ разработан таким образом?

Да.

Я знаю, что для Java все наоборот (оценивается слева направо).

Да, Java отличается.


Вот несколько рекомендаций, которые помогут вам понять оценкувыражений C:

  1. Изучите правила приоритета операторов и ассоциативности.Для «простых» выражений эти правила сообщают вам практически все, что вам нужно знать об оценке выражения.Учитывая a + b * c, b умножается на c, а затем продукт добавляется к a, из-за более высокого приоритета * над +.Учитывая a + b + c, a добавляется к b, а затем сумма добавляется к c, потому что + ассоциируется слева направо.

  2. За исключениемассоциативность (как упомянуто в пункте 1), старайтесь не использовать слова «слева направо» или «справа налево» для оценки вообще .C не имеет ничего общего с оценкой слева направо или справа налево.(Очевидно, что Java отличается.)

  3. Побочные эффекты возникают из-за сложностей.(Когда я говорил «простые» выражения »в пункте 1, я в основном имел в виду« выражения без побочных эффектов ».) К побочным эффектам относятся (а) вызовы функций, (б) назначения с =, (в) назначения с +=, -= и т. Д., И, конечно, (d) увеличивается / уменьшается с ++ и --.(Если имеет значение, когда вы выбираете из переменной, что обычно имеет место только для переменных, квалифицированных как volatile, мы можем добавить (e) выборки из volatile переменных в список.) В общем Вы не можете сказать, когда происходят побочные эффекты .Постарайтесь не заботиться.Пока вам все равно (если ваша программа нечувствительна к порядку, в котором побочные эффекты имеют значение), это не имеет значения.Но если ваша программа чувствительна к , она, вероятно, не определена.(Подробнее см. Пункты 4 и 5 ниже.)

  4. Вы никогда не должны иметь двух побочных эффектов в одном выражении, которые пытаются изменить одну и ту же переменную.(Примеры: i = i++, a++ + a++.) Если вы это сделаете, выражение не определено.

  5. С одним классом исключений у вас никогда не должно быть побочного эффекта, который пытается изменить переменную, которая также используется в другом месте в том же выражении.(Пример: a == --a.) Если вы это сделаете, выражение не определено.Исключение составляют случаи, когда доступное значение используется для вычисления значения, которое будет сохранено, как в i = i + 1.

...