本节是《if 语句与语句块》的延续,我们将讨论使用 if 语句时常见的一些问题。
嵌套 if 语句与悬垂 else 问题
可以将 if 语句嵌套在另一个 if 语句内部:
#include <iostream>
int main()
{
    std::cout << "Enter a number: ";
    int x{};
    std::cin >> x;
    if (x >= 0)               // 外层 if
        if (x <= 20)          // 内层 if
            std::cout << x << " is between 0 and 20\n";
    return 0;
}
然而,考虑以下程序:
#include <iostream>
int main()
{
    std::cout << "Enter a number: ";
    int x{};
    std::cin >> x;
    if (x >= 0)               // 外层 if
        if (x <= 20)          // 内层 if
            std::cout << x << " is between 0 and 20\n";
    else                      // 这个 else 属于哪个 if?
        std::cout << x << " is negative\n";
    return 0;
}
上述代码引入了名为“悬垂 else”的潜在歧义:该 else 究竟与外层 if 还是内层 if 配对?
规则:else 与同一语句块中最后一个尚未匹配的 if 配对。因此,上例中的 else 与内层 if 匹配,等效于:
#include <iostream>
int main()
{
    std::cout << "Enter a number: ";
    int x{};
    std::cin >> x;
    if (x >= 0)
    {
        if (x <= 20)
            std::cout << x << " is between 0 and 20\n";
        else                        // 与内层 if 匹配
            std::cout << x << " is negative\n";
    }
    return 0;
}
这将导致错误输出:
Enter a number: 21
21 is negative
为避免在嵌套 if 语句时出现歧义,应将内层 if 显式置于语句块中,从而可将 else 明确关联到外层或内层 if:
#include <iostream>
int main()
{
    std::cout << "Enter a number: ";
    int x{};
    std::cin >> x;
    if (x >= 0)
    {
        if (x <= 20)
            std::cout << x << " is between 0 and 20\n";
        else
            std::cout << x << " is greater than 20\n";
    }
    else
        std::cout << x << " is negative\n";
    return 0;
}
扁平化嵌套 if 语句
嵌套 if 语句常可通过重构逻辑或使用逻辑运算符(见 6.8 节《逻辑运算符》)来扁平化。减少嵌套可降低出错概率。
例如,上述示例可扁平化为:
#include <iostream>
int main()
{
    std::cout << "Enter a number: ";
    int x{};
    std::cin >> x;
    if (x < 0)
        std::cout << x << " is negative\n";
    else if (x <= 20)   // 仅当 x >= 0 时求值
        std::cout << x << " is between 0 and 20\n";
    else                // 仅当 x > 20 时求值
        std::cout << x << " is greater than 20\n";
    return 0;
}
再举一例,使用逻辑运算符在单个 if 语句中检查多重条件:
#include <iostream>
int main()
{
    std::cout << "Enter an integer: ";
    int x{};
    std::cin >> x;
    std::cout << "Enter another integer: ";
    int y{};
    std::cin >> y;
    if (x > 0 && y > 0)          // && 为逻辑与,检查两条件是否均为真
        std::cout << "Both numbers are positive\n";
    else if (x > 0 || y > 0)     // || 为逻辑或,检查是否至少一个条件为真
        std::cout << "One of the numbers is positive\n";
    else
        std::cout << "Neither number is positive\n";
    return 0;
}
空语句
空语句是仅由一个分号构成的表达式语句:
if (x > 10)
    ; // 空语句
空语句不执行任何操作,常用于语法上要求存在语句而程序员无需任何动作之处。为了提高可读性,空语句通常单独成行。本章后续介绍循环时,将展示有意使用空语句的示例。
空语句很少与 if 语句配合使用,却可能因疏忽而引入错误。例如:
if (nuclearCodesActivated()); // 行尾意外加分号
    blowUpTheWorld();
由于分号的存在,代码等价于:
if (nuclearCodesActivated())
    ;                          // 空语句
blowUpTheWorld();              // 始终执行
警告
切勿在 if 语句末尾误加分号,否则原本应条件执行的语句将无条件执行,即使它们位于块内亦如此。
提示
在 Python 中,pass 关键字充当空语句,常用于占位,便于后续实现。因其为单词而非符号,误用概率低且易于搜索定位。
for x in [0, 1, 2]:
    pass               # 将来补全
在 C++ 中,可通过预处理器模拟 pass:
#define PASS
void foo(int x, int y)
{
    if (x > y)
        PASS;
    else
        PASS;
}
int main()
{
    foo(4, 7);
    return 0;
}
为与其他 C++ 语句保持一致,PASS 需以分号结尾。预处理器将 PASS 移除,分号被解释为空语句。
条件表达式中的 == 与 = 误用
在条件中应使用 == 进行相等测试,而非赋值运算符 =。例如:
#include <iostream>
int main()
{
    std::cout << "Enter 0 or 1: ";
    int x{};
    std::cin >> x;
    if (x = 0) // 误用赋值而非相等比较
        std::cout << "You entered 0\n";
    else
        std::cout << "You entered 1\n";
    return 0;
}
该程序虽可编译运行,但部分情况下结果错误:
Enter 0 or 1: 0
You entered 1
事实上,程序始终输出 “You entered 1”。原因是 x = 0 先将 0 赋给 x,然后表达式求值为 x 的值 0,对应布尔值 false,故条件恒为假,else 分支始终执行。
