我不假思索地编写了一些代码来检查结构的所有值是否都设置为0.为了实现这一点,我使用了:
bool IsValid() {
return !(0 == year == month == day == hour == minute == second);
}
其中所有struct成员都是unsigned short类型。我使用代码作为更大测试的一部分,但注意到它对于不等于零的值返回false,对于全部等于零的值则返回true - 与我预期的相反。
我将代码更改为:
bool IsValid() {
return (0 != year) || (0 != month) || (0 != day) || (0 != hour) || (0 != minute) || (0 != second);
}
但是想知道是什么导致了奇怪的行为。这是优先的结果吗?我试过谷歌这个答案,但没有发现任何东西,如果有任何术语来描述我想知道它的结果。
我使用VS9和VS8编译了代码。
答案 0 :(得分:28)
==
从左到右分组,所以如果所有值都为零,那么:
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
,正如您所期望的那样。
答案 1 :(得分:15)
这种行为不应该被视为奇怪。 ==
(以及大多数但不是所有二元运算符)的语法规则指定了从左到右的分组,因此您的原始表达式等同于:
!((((((0 == year) == month) == day) == hour) == minute) == second)
请注意,与整数类型相比,值bool
的{{1}}表达式将提升为true
,值1
将提升为false
。 (在C中,等于运算符的结果在任何情况下都是0
,其值为int
或1
。)
这意味着,例如,如果0
为零且((0 == year) == month)
为1,或year
为非零但month
,则year
为真}是零,否则为假。
答案 2 :(得分:8)
你必须考虑它的评估方式......
a == b == c
询问其中两个是否相等(a
和b
),然后将该布尔结果与第三个值c
进行比较!它不是将前两个值与第三个值进行比较。超出2个参数的任何东西都不会像你明显的那样链接。
无论它值多少,因为C ++在布尔上下文中认为非0值为“true”,你可以简单地表达你想要的东西:
return year && month && day && hour && minute && second;
(注意:您的修改后的代码会说“月”两次并且不会测试分钟)。
回到链式==
:用户自定义类型和运算符重载可以创建一个按预期进行比较的类(它甚至可以允许像{{1按照数学中的方式“工作”,但是创造一些特殊的东西会让其他程序员感到困惑,因为这些程序员已经知道这些东西在C ++中对于内置类型有用(奇怪)。如果您热衷于深入学习C ++,那么值得做一个十分钟/二十分钟的编程练习(提示:您需要比较运算符返回一个代理对象,该代理对象会记住下一个比较的左侧值是什么操作者)。
最后,有时候这些“怪异”的布尔表达式很有用:例如,0 <= x < 10
可能用英语表示为“a(a == b)和(c == d),OR(a!= b)和(c!= d)“,或者”a和b的等价与c和d的等价(无论真或假无关紧要)相同“。这可能会模拟现实世界的情况,比如双重约会场景:如果喜欢/不喜欢b(他们的约会对象)喜欢/不喜欢d,那么他们要么会闲逛又玩得开心或者叫它快速退出无论如何都是无痛的...否则一对夫妇将会有一段非常繁琐的时间......因为这些事情都有意义,编译器不可能知道你不打算创建这样的表达式。
答案 3 :(得分:1)
如果操作数相等,则==
运算符的返回值为1
,因此无论从左到右还是从右到左读取它,这都不会达到预期效果。
所以如果您对所有值都是1
感兴趣,那么这只能在类似的测试中起作用。
要表达一个较短的表达,因为你似乎只对year || day || ...
答案 4 :(得分:1)
你的错误就是用等号写下一个数学表达式,不假思索地假设计算机会执行你想要的测试 - 人类数学家会看到这些符号的含义。计算机的作用(根据语言的定义)是执行一系列离散比较,每个比较返回true
或false
- 以及true
或{{1}然后将用于下一次比较。您没有将所有这些变量与0进行比较,您将每个变量(其中两个变量)与比较另外两个变量的结果进行比较。