Являются ли закодированные логические операторы короткими законами? И порядок оценки?

Соответствует ли стандарт ANSI логическим операторам короткое замыкание на C или C ++?

Я смущен, потому что я помню книгу K & R, в которой ваш код не должен зависеть от того, как эти операции замыкаются, потому что они не могут. Может кто-нибудь, пожалуйста, укажет, где в стандарте сказано, что логические операторы всегда закорочены? Меня больше всего интересует C ++, ответ также для C будет замечательным.

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

Указывает ли стандарт на порядок оценки этого выражения?

if( functionA() && functionB() && functionC() ) cout<<"Hello world"; 

Да, для операторов требуется короткое замыкание и порядок оценки || и && в стандартах C и C ++.

Стандарт C ++ говорит (в стандарте C должно быть эквивалентное предложение):

1.9.18

При оценке следующих выражений

 a && b a || b a ? b : c a , b 

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

В C ++ есть дополнительная ловушка: short-circuiting НЕ применяется к типам, которые перегружают операторы || и && .

Сноска 12: Операторы, указанные в этом параграфе, являются встроенными операторами, как описано в разделе 5. Когда один из этих операторов перегружен (статья 13) в допустимом контексте, обозначая, таким образом, определяемую пользователем операторную функцию, выражение обозначает вызов функции, а операнды образуют список аргументов, без подразумеваемой точки последовательности между ними.

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

Оценка короткого замыкания и порядок оценки являются обязательным семантическим стандартом как на C, так и на C ++.

Если бы это было не так, такой код не был бы распространенным идиомом

  char* pChar = 0; // some actions which may or may not set pChar to something if ((pChar != 0) && (*pChar != '\0')) { // do something useful } 

Раздел 6.5.13 Логический оператор AND спецификации C99 (ссылка PDF)

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

Аналогично, раздел 6.5.14 Логический оператор OR говорит

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

Аналогичную формулировку можно найти в стандартах C ++, проверьте раздел 5.14 в этой черновике . Как отмечает чек в другом ответе, если вы переопределите && или ||, то оба операнда должны быть оценены, так как они становятся обычным вызовом функции.

Да, он предусматривает, что (как порядок оценки, так и короткое замыкание). В вашем примере, если все функции возвращают true, порядок вызовов выполняется строго из функции A, затем functionB, а затем functionC. Используется для этого как

 if(ptr && ptr->value) { ... } 

То же самое для оператора запятой:

 // calls a, then b and evaluates to the value returned by b // which is used to initialize c int c = (a(), b()); 

Говорят между левым и правым операндом && , || , и между первым и вторым / третьим операндом ?: (условный оператор) является «точкой последовательности». Любые побочные эффекты оцениваются полностью до этого момента. Таким образом, это безопасно:

 int a = 0; int b = (a++, a); // b initialized with 1, and a is 1 

Обратите внимание, что оператор запятой не следует путать с синтаксической запятой, используемой для разделения вещей:

 // order of calls to a and b is unspecified! function(a(), b()); 

Стандарт C ++ говорит в 5.14/1 :

Операторы && группируются слева направо. Операнды неявно преобразуются в тип bool (раздел 4). Результат верен, если оба операнда верны и false в противном случае. В отличие от &, && гарантирует оценку слева направо: второй операнд не оценивается, если первый операнд является ложным.

И в 5.15/1 :

|| группы операторов слева направо. Операнды оба неявно преобразуются в bool (раздел 4). Он возвращает true, если любой из его операндов истинен, а false – в противном случае. В отличие от |, || гарантирует оценку слева направо; кроме того, второй операнд не оценивается, если первый операнд оценивается как истинный.

Это говорит как для тех,

В результате получается bool. Все побочные эффекты первого выражения, кроме уничтожения временных рядов (12.2), происходят до того, как будет оценено второе выражение.

В дополнение к этому, 1.9/18 говорит

При оценке каждого из выражений

  • a && b
  • a || b
  • a ? b : C
  • a , b

используя встроенное значение операторов в этих выражениях (5.14, 5.15, 5.16, 5.18), после оценки первого выражения существует точка последовательности.

Прямо от старого старого K & R:

C гарантирует, что && и || оцениваются слева направо – мы скоро увидим случаи, когда это имеет значение.

Будьте очень осторожны.

Для типов POD это операторы быстрого доступа.

Но если вы определяете эти операторы для своих собственных classов, они не являются ярлыками. Из-за этой семантической разницы в их использовании в этих разных обстоятельствах рекомендуется не определять эти операторы.

Для оператора && и оператора || для типов POD порядок оценки оставлен вправо (иначе короткая резка будет сложной 🙂 Но для перегруженных операторов, которые вы определяете, это в основном синтаксический сахар для определения метода, и поэтому порядок оценки параметров не определен.

Если вы доверяете Википедии:

[ && и || ] семантически отличны от битовых операторов & и | потому что они никогда не будут оценивать правый операнд, если результат можно определить только слева

http://en.wikipedia.org/wiki/C_(programming_language)#Characteristics

Ваш вопрос сводится к приоритету и ассоциативности операторов C ++ . В принципе, в выражениях с несколькими операторами и без скобок компилятор строит дерево выражений, следуя этим правилам.

Для приоритета, когда у вас есть что-то вроде A op1 B op2 C , вы можете группировать вещи как (A op1 B) op2 C или A op1 (B op2 C) . Если op1 имеет более высокий приоритет, чем op2 , вы получите первое выражение. В противном случае вы получите второй.

Для ассоциативности, когда у вас есть что-то вроде A op B op C , вы можете снова группировать thins как (A op B) op C или A op (B op C) . Если op оставил ассоциативность, мы получим первое выражение. Если он имеет правую ассоциативность, мы получаем вторую. Это также работает для операторов с одинаковым уровнем приоритета.

В этом конкретном случае && имеет более высокий приоритет, чем || , поэтому выражение будет оцениваться как (a != "" && it == seqMap.end()) || isEven (a != "" && it == seqMap.end()) || isEven .

Сам заказ является «слева направо» в форме дерева выражений. Итак, сначала мы оценим a != "" && it == seqMap.end() . Если это правда, все выражение истинно, иначе мы идем к isEven . Процедура, конечно, повторяется сама по себе в левом подвыражении.


Интересные лакомые кусочки, но концепция приоритета уходит своими корнями в математическую нотацию. То же самое происходит в a*b + c , где * имеет более высокий приоритет, чем + .

Еще более интересным / неясным, для выражения unparenthasiszeed A1 op1 A2 op2 ... opn-1 An , где все операторы имеют одинаковый приоритет, число деревьев двоичных выражений, которые мы могли бы сформировать, дается так называемыми каталонскими числами . При больших n они растут очень быстро. d

  • Логические операторы ("и", "или") в партии DOS
  • Является ли использование && короткого замыкания безопасным в .NET?
  • В чем разница между логическим и условным И, ИЛИ в C #?
  • Is (4> y> 1) допустимый оператор в C ++? Как вы оцениваете это, если так?
  • Различия в булевых операторах: & vs && и | vs ||
  • !! c, является двумя НЕ?
  • Interesting Posts

    ПРЕДУПРЕЖДЕНИЕ: очистка небезопасного значения значения стиля

    Как установить Sqlite3 как нечувствительный к регистру при сравнении строк?

    отказоустойчивый плагин не будет работать в одном проекте, но будет работать на другом – почему?

    Excel – количество видимых ячеек, содержащих определенную строку.

    Какая разница между каталогами .ssh и .ssh2

    FCM с AWS SNS

    Неуправляемые функции оптимизируются?

    Как заставить диск FireWire отображаться как диск (в отличие от общей папки) в виртуальной машине VMWare Windows XP на моем Mac?

    Как автоматизировать настройку Chrome в качестве браузера Windows по умолчанию?

    Сортировка списка из другого идентификатора списка

    Замена кода с помощью обработчика annotations

    После включения raid0 синий экран смерти

    css framework для приложения с существующей таблицей стилей

    Панель вкладок «Блокнот ++» скрывается

    Как создать образ раздела Windows, чтобы впоследствии просмотреть файлы?

    Давайте будем гением компьютера.