Chaining Bool values give opposite result to expected

元气小坏坏 提交于 2019-12-18 18:55:19

问题


Unthinkingly I wrote some code to check that all the values of a struct were set to 0. To accomplish this I used:

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

where all struct members were of type unsigned short. I used the code as part of a larger test but noticed that it was returning false for values differing from zero, and true for values that were all equal to zero - the opposite of what I expected.

I changed the code to read:

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

But would like to know what caused the odd behaviour. Is it a result of precedence? I've tried to Google this answer but found nothing, if there's any nomenclature to describe the result I'd love to know it.

I compiled the code using VS9 and VS8.


回答1:


== groups from left to right, so if all values are zero then:

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

And so on.

In general, x == y == z is not equivalent to x == y && x == z as you seem to expect.




回答2:


The behaviour shouldn't be seen as odd. The grammar rules for == (and most but not all binary operators) specify left to right grouping so your original expression is equivalent to:

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

Note that when compared to an integer type a bool expression with value true will promote to 1 and with value false will promote to 0. (In C the result of the equality operator is an int in any case with a value or either 1 or 0.)

This means that, for example, ((0 == year) == month) will be true if year is zero and month is one or if year is non-zero but month is zero and false otherwise.




回答3:


You have to consider how it's evaluated...

a == b == c

is asking if two of them are equal (a and b), then comparing that boolean result to the third value c! It is NOT comparing the first two values with the third. Anything beyond 2 arguments won't chain as you evidently expect.

For whatever it's worth, because C++ considers non-0 values to be "true" in a boolean context, you can express what you want simply as:

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

(note: your revised code says "month" twice and doesn't test minute).

Back to the chained ==s: with user-defined types and operator overloading you can create a class that compares as you expect (and it can even allow things like 0 <= x < 10 to "work" in the way it's read in mathematics), but creating something special will just confuse other programmers who already know the (weird) way these things work for builtin types in C++. Worth doing as a ten/twenty minute programming exercise though if you're keen to learn C++ in depth (hint: you need the comparison operators to return a proxy object that remembers what will be the left-hand-side value for the next comparison operator).

Finally, sometimes these "weird" boolean expressions are useful: for example, a == b == (c == d) might be phrased in English as "either (a == b) and (c == d), OR (a != b) and (c != d)", or perhaps "the equivalence of a and b is the same as the equivalence of c and d (whether true or false doesn't matter)". That might model real world situations like a double-dating scenario: if a likes/dislikes b (their date) as much as c likes/dislikes d, then they'll either hang around and have a nice time or call it quits quickly and it's painless either way... otherwise one couple will have a very tedious time of it.... Because these things can make sense, it's impossible for the compiler to know you didn't intend to create such an expression.




回答4:


Your error here is writing a mathematical expression using equals signs, and unthinkingly supposing that the computer will perform the test you meant - what a human mathematician would see as the meaning of those symbols. What the computer does (as per the definition of the language) is to perform a series of discrete comparisons, each of which returns true or false - and this true or false is then used in the next comparison. You aren't comparing all of those variables to 0, you're comparing each (bar two of them) to the result of comparing another two of the said variables.




回答5:


The return of the == operator is 1 if the operands are equal, so regardless wether this is read from left to right or right to left, this will not do what you expect.

so this could only work in an analogous test if you would be interested if all values are 1.

And to have a shorter expression since you seem interested in that just do year || day || ...



来源:https://stackoverflow.com/questions/5939077/chaining-bool-values-give-opposite-result-to-expected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!