具有多个条件 IF 语句的奇怪行为

Strange behaviour with multiple condition IF statment

我注意到,在组合 !=&& 运算符时,我偶然发现了 if 函数的奇怪行为。例如,我有两个 std::string 对象,我想检查它们是否不是 "ffff""0000",然后继续进行一些计算。

代码如下所示:

std::string sentData("ffff")
std::string sentAddr("060C")
if (sentData == "ffff") 
    cout << "A 1. Same" << endl;
else 
    cout << "A 1. Different" << endl;
if (sentAddr == "0000") 
    cout << "A 2. Same" << endl;
else 
    cout << "A 2. Different" << endl;
if ((sentData == "ffff") && (sentAddr == "0000")) 
    cout << "A &&. Same" << endl;
else 
    cout << "A &&. Different" << endl;

if (sentData != "ffff") 
    cout << "B 1. Different" << endl;
else 
    cout << "B 1. Same" << endl;
if (sentAddr != "0000") 
    cout << "B 2. Different" << endl;
else 
    cout << "B 2. Same" << endl;
if ((sentData != "ffff") && (sentAddr != "0000")) 
    cout << "B &&. Different" << endl;
else 
    cout << "B &&. Same" << endl;

理论上,我认为它应该产生相同的结果......但事实并非如此。最后一个 if 函数将 && 视为 ||(我不知道为什么),因此我进入最后一个 if 语句,即使只有一个答案是正确的。下面是一些答案。

正常工作:

sentData: ffff  sentAddr: 0000
A 1. Same
A 2. Same
A &&. Same
B 1. Same
B 2. Same
B &&. Same

sentData: ffdf  sentAddr: 060e
A 1. Different
A 2. Different
A &&. Different
B 1. Different
B 2. Different
B &&. Different

工作错误:

sentData: ffff  sentAddr: 060c
A 1. Same
A 2. Different
A &&. Different
B 1. Same
B 2. Different
B &&. Same

sentData: fb8c  sentAddr: 0000
A 1. Different
A 2. Same
A &&. Different
B 1. Different
B 2. Same
B &&. Same

因此,如果我在 if ((sentData != "ffff") && (sentAddr != "0000")) 中使用 sentData: fb8c sentAddr: 0000,我会得到 if (TRUE && FALSE),但显然它仍然进入 if 语句。

问:有谁知道为什么吗?

我问这个是因为我想避免编写这样难看的代码:

if (!((sentData == "ffff") && (sentAddr == "0000"))) {
    // do stuff
}

if ((sentData == "ffff") && (sentAddr == "0000")) {
    // nothing to do
} else {
    // do stuff
}

你认为!a && !b!(a && b)的反义词是错误的。

这是因为分配或 un-distributing 对布尔运算的否定要求您将布尔运算翻转为它的对偶并对各个内项取反,反之亦然。

这被称为De Morgan's Law,是布尔代数中的基本定律。

因此对偶:

(a && b)

实际上是:

(!a || !b)

和对偶:

(!a && !b)

实际上是:

(a || b)

这是工作代码:

#include <iostream>
#include <string>

int main()
{
    using namespace std;

    std::string sentData("ffff");
    std::string sentAddr("060C");

    auto a = (sentData == "ffff");  // true
    auto b = (sentAddr == "0000");  // false

    if (a)              cout << "A 1. Same" << endl;
    else                cout << "A 1. Different" << endl;

    if (b)              cout << "A 2. Same" << endl;
    else                cout << "A 2. Different" << endl;

    if (a && b)         cout << "A &&. Same" << endl;
    else                cout << "A &&. Different" << endl;

    if (!a)             cout << "B 1. Different" << endl;
    else                cout << "B 1. Same" << endl;

    if (!b)             cout << "B 2. Different" << endl;
    else                cout << "B 2. Same" << endl;

    if ((!a || !b))     cout << "B &&. Different" << endl;
    else                cout << "B &&. Same" << endl;
}

See it live on Coliru.

既然你似乎还有点困惑,我会尝试一种不同于@VermillionAzure 的精彩回答所采用的方法。


考虑以下源代码,它与您的测试条件完全相同,减去不相关的,但输出描述不同:

if ((sentData == "ffff") && (sentAddr == "0000")) 
    cout << "both are equal" << endl;
else 
    cout << "at least one is different" << endl;

if ((sentData != "ffff") && (sentAddr != "0000")) 
    cout << "both are different" << endl;
else 
    cout << "at least one is equal" << endl;

这是输出:

sentData: ffff  sentAddr: 0000
both are equal
at least one is equal

sentData: ffdf  sentAddr: 060e
at least one is different
both are different

sentData: ffff  sentAddr: 060c
at least one is different
at least one is equal

sentData: fb8c  sentAddr: 0000
at least one is different
at least one is equal

如您所见,输出不再出现不一致。

由于我没有更改您的任何测试条件,而只更改了打印输出,因此现在的描述必然准确 wrt。你的测试条件.

的实际意义

如果你想重写这个

if ((sentData == "ffff") && (sentAddr == "0000")) 
    cout << "both are equal" << endl;
else 
    cout << "at least one is different" << endl;

使用!=,则应按如下方式进行:

if (!((sentData != "ffff") || (sentAddr != "0000"))) 
    cout << "both are equal" << endl;
else 
    cout << "at least one is different" << endl;

这是应用 De Morgan's law 的示例。


这两个都

if (!((sentData == "ffff") && (sentAddr == "0000"))){
    // do stuff
}

// note: please use brackets consistently
if ((sentData == "ffff") && (sentAddr == "0000")) {
} else {
    // do stuff
}

可以改写为

if ((sentData != "ffff") || (sentAddr != "0000")){
    // do stuff
}

附录:

您对问题的最后编辑包括以下陈述:

So if I use sentData: fb8c sentAddr: 0000 in if ((sentData != "ffff") && (sentAddr != "0000")) I get if (TRUE && FALSE), but it still enters the if statement.

如果"it still enters the if statement"你的意思是它走第一个分支,那你就错了。事实上,您的输出显示它打印 "B &&. Same",这是第二个分支 (else).