Целочисленные значения Bool дают противоположный результат ожидаемому

Непонятно я написал код, чтобы проверить, что все значения структуры были установлены равными 0. Для этого я использовал:

bool IsValid() {
    return !(0 == year == month == day == hour == minute == second);
}

где все члены структуры имели тип unsigned short. Я использовал код как часть более крупного теста, но заметил, что он возвращал значение false для значений, отличных от нуля, и true для значений, которые были равны нулю - напротив того, что я ожидал.

Я изменил код, чтобы читать:

bool IsValid() {
    return (0 != year) || (0 != month) || (0 != day) || (0 != hour) || (0 != minute) || (0 != second);
}

Но хотелось бы знать, что вызвало нечетное поведение. Это результат приоритета? Я попытался ответить на этот ответ Google, но ничего не нашел, если есть какая-либо номенклатура, чтобы описать результат, который я хотел бы узнать.

Я скомпилировал код, используя VS9 и VS8.

Ответы

Ответ 1

== группы слева направо, поэтому, если все значения равны нулю, то:

0 == year // true
(0 == year) == month // false, since month is 0 and (0 == year) converts to 1
((0 == year) == month) == day // true

И так далее.

В общем случае x == y == z не эквивалентен x == y && x == z, как вы, кажется, ожидаете.

Ответ 2

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

!((((((0 == year) == month) == day) == hour) == minute) == second)

Обратите внимание, что по сравнению с целым типом выражение bool со значением true будет продвигаться до 1 и со значением false будет продвигаться до 0. (В C результатом оператора равенства является int в любом случае со значением или либо 1, либо 0.)

Это означает, что, например, ((0 == year) == month) будет истинным, если year равно нулю и month является одним или если year отличен от нуля, но month равен нулю и false в противном случае.

Ответ 3

Вы должны рассмотреть, как он оценивается...

a == b == c

спрашивает, являются ли два из них равными (a и b), а затем сравнивая этот логический результат с третьим значением c! Это НЕ сравнение первых двух значений с третьим. Все, что находится за пределами 2 аргументов, не будет цепочки, как вы, очевидно, ожидаете.

Что бы это ни стоило, потому что С++ считает, что значения не-0 являются "истинными" в булевом контексте, вы можете выразить то, что хотите, просто как:

return year && month && day && hour && minute && second;

(обратите внимание: ваш обновленный код дважды говорит "месяц" и не проверяет минуту).

Вернемся к цепочке == s: с пользовательскими типами и перегрузкой оператора вы можете создать класс, который сравнивается по мере того, как вы ожидаете (и он может даже позволить таким вещам, как 0 <= x < 10 "работать" таким образом, чтобы он читал в математике), но создание чего-то особенного будет просто путать других программистов, которые уже знают (странный) способ, которым эти вещи работают для встроенных типов на С++. Стоит делать 10-20-минутное программирование, хотя, если вы хотите изучить С++ по глубине (подсказка: вам нужны операторы сравнения, чтобы вернуть прокси-объект, который помнит, что будет левым для следующего сравнения оператор).

Наконец, иногда эти "странные" булевы выражения полезны: например, a == b == (c == d) может быть сформулирован на английском языке как "либо (a == b), и (c == d), OR (a!= b) и (c!= d)", или, возможно, "эквивалентность a и b такая же, как эквивалентность c и d (истинна или ложна не имеет значения)". Это может привести к моделированию ситуаций в реальном мире, таких как сценарий двойного знакомства: если нравится/не нравится b (их дата) до тех пор, пока c не нравится/не нравится d, тогда они либо будут болтаться, либо хорошо проводить время, либо называть его быстрым и быстрым это безболезненно в любом случае... иначе у одной пары будет очень утомительное время... Потому что эти вещи могут иметь смысл, невозможно, чтобы компилятор знал, что вы не собираетесь создавать такое выражение.

Ответ 4

Возврат оператора == равен 1, если операнды равны, поэтому, несмотря на то, что это читается слева направо или справа налево, это не будет делать то, что вы ожидаете.

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

И чтобы иметь более короткое выражение, так как вы заинтересованы в том, что просто year || day || ...

Ответ 5

Ваша ошибка здесь заключается в написании математического выражения с использованием знаков равенства и немыслимо, предполагая, что компьютер выполнит ваш тест, что человеческий математик увидит в качестве значения этих символов. Что делает компьютер (в соответствии с определением языка), это выполнить серию дискретных сравнений, каждый из которых возвращает true или false - и этот true или false затем используется в следующем сравнении, Вы не сравниваете все эти переменные с 0, вы сравниваете каждый (два из них) с результатом сравнения двух других переменных.