链接布尔值会给出与预期相反的结果

Chaining Bool values give opposite result to expected

本文关键字:结果 布尔值 链接      更新时间:2023-10-16

我不假思索地编写了一些代码来检查结构的所有值是否都设置为 0。为此,我使用了:

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

其中所有结构成员的类型均为无符号短。我将代码用作更大测试的一部分,但注意到它对于不同于零的值返回 false,对于全部等于零的值返回 true,这与我的预期相反。

我将代码更改为:

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

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

我使用 VS9 和 VS8 编译了代码。

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

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

这种行为不应该被视为奇怪。==(以及大多数但不是全部)的语法规则指定从左到右的分组,因此原始表达式等效于:

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

请注意,与整数类型相比,具有值 truebool 表达式将提升为 1,值为 false 将提升为 0 。(在 C 中,相等运算符的结果在任何情况下都是具有值或 10int

这意味着,例如,如果year为零且month为 1,或者如果 year 为非零但month为零,否则为假,则((0 == year) == month)为真。

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

a == b == c

询问其中两个是否相等(ab ),然后将该布尔结果与第三个值进行比较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),要么(a != b)和(c != d)",或者也许"a和b的等价性与c和d的等价相同(无论真假都无关紧要)"。 这可能会模拟现实世界的情况,就像双重约会场景一样:如果 a 喜欢/不喜欢 b(他们的约会)和 c 喜欢/不喜欢 d 一样多,那么他们要么闲逛,玩得很开心,要么很快就退出了,无论哪种方式都无痛......否则一对夫妇将度过一段非常乏味的时光...... 因为这些事情是有意义的,所以编译器不可能知道你不打算创建这样的表达式。

你的错误是用等号写一个数学表达式,并且不假思索地假设计算机会执行你的意思——人类数学家会认为这些符号的含义。计算机所做的(根据语言的定义)是执行一系列离散比较,每个比较返回truefalse - 然后在下一次比较中使用这种truefalse。您不是将所有这些变量与 0 进行比较,而是将每个变量(其中两个除外)与比较另外两个所述变量的结果进行比较。

如果操作数相等,则==运算符的返回值是1的,因此无论从左到右还是从右到左读取,这都不会执行您的预期。

因此,如果您有兴趣,这只能在类似的测试中起作用 1 .

并且有一个更短的表达,因为你似乎对此感兴趣,只是做year || day || ...