链接 Bool 值给出与预期相反的结果

问题描述 投票:0回答:5

我不假思索地编写了一些代码来检查结构体的所有值是否都设置为 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);
}

但想知道是什么导致了奇怪的行为。是优先权的结果吗?我试图用谷歌搜索这个答案,但一无所获,如果有任何术语来描述结果,我很想知道。

我使用VS9和VS8编译代码。

c++ c boolean operator-precedence
5个回答
32
投票

==
从左到右分组,因此如果所有值均为零,则:

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
,正如您所期望的那样。


15
投票

这种行为不应被视为奇怪。

==
(以及大多数但不是全部二元运算符)的语法规则指定从左到右分组,因此您的原始表达式相当于:

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

请注意,与整数类型相比,具有值

bool
true
表达式将提升为
1
,而具有值
false
将提升为
0
。 (在 C 语言中,相等运算符的结果在任何情况下都是带有值的
int
1
0
。)

这意味着,例如,如果

((0 == year) == month)
为零且
year
为 1,或者如果
month
非零但
year
为零,则
month
将为 true,否则为 false。


8
投票

你必须考虑如何评估它......

a == b == c

询问其中两个是否相等(

a
b
),然后将该布尔结果与第三个值
c
进行比较! 它不是将前两个值与第三个值进行比较。 超过 2 个参数的任何内容都不会像您显然期望的那样链接。

无论它的价值如何,因为 C++ 在布尔上下文中认为非 0 值是“true”,所以您可以简单地表达您想要的内容:

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

(注意:您修改后的代码说“月”两次,并且不测试分钟)。

回到链式

==
:使用用户定义的类型和运算符重载,您可以创建一个按照您的预期进行比较的类(它甚至可以允许像
0 <= x < 10
这样的东西按照其读取的方式“工作”数学),但是创建一些特殊的东西只会让其他已经知道这些东西在 C++ 中的内置类型上工作的(奇怪的)方式的程序员感到困惑。 如果您热衷于深入学习 C++,则作为十/二十分钟的编程练习值得做(提示:您需要比较运算符返回一个代理对象,该对象记住下一次比较的左侧值是什么操作员)。

最后,有时这些“奇怪”的布尔表达式很有用:例如,

a == b == (c == d)
在英语中可能会表达为“要么(a == b)和(c == d),OR(a!= b)和( c != d)”,或者“a 和 b 的等价性与 c 和 d 的等价性相同(真假无关紧要)”。 这可能会模拟现实世界的情况,例如双重约会场景:如果a喜欢/不喜欢b(他们的约会对象)与c喜欢/不喜欢d一样多,那么他们要么会闲逛并度过愉快的时光,要么很快就退出并不管怎样,这都是无痛的...否则一对夫妇将会度过一段非常乏味的时光...因为这些事情是有意义的,所以编译器不可能知道你不打算创建这样的表达式。


1
投票

您在这里的错误是使用等号编写数学表达式,并且不假思索地假设计算机将执行您想要的测试 - 人类数学家会看到这些符号的含义。计算机所做的(根据语言的定义)是执行一系列离散比较,每个比较都返回

true
false
- 然后这个
true
false
然后在下一个中使用比较。您并不是将所有这些变量与 0 进行比较,而是将每个变量(除了其中两个)与比较另外两个所述变量的结果进行比较。


1
投票

如果操作数相等,

==
运算符的返回值为
1
,因此无论从左到右还是从右到左读取,都不会达到您的预期。

因此,如果您对所有值都感兴趣,则这只能在类似的测试中起作用。


并且要表达更简短的内容,因为您似乎对此感兴趣,只需这样做

1

    

© www.soinside.com 2019 - 2024. All rights reserved.