6

是否有任何保证,一个if-else if-else if-else块的 ifs 会按照它们被写入的顺序进行测试。

我之所以这么问,是因为我经常尝试通过将最常见的情况放在首位来优化我的代码,并且我想知道编译器所做的一些优化是否会改变 if 的测试顺序。

所以,如果我正在编写这样的代码:

    if (cond1) // First if (for the case I have the most often)
    {
            doSomething1();
    }
    else if (cond2) // Second if (for the second case I have the most often)
    {
            doSomething2();
    }
    else if (cond3) // Third if (for the third case I have the most often)
    {
            doSomething3();
    }
    else
    {
            doElse();
    }

是否有任何保证在编译(用于发布)之后,将测试第一个 if,然后是第二个 if,然后是第三个 if(如果条件都不为真,则最后执行 else)。

我知道在调试时,ifs 是按照我编写它们的顺序执行的,但是当程序编译发布时它会保持不变(我主要使用最新版本的 g++ 和 Visual Studio)。

此外,由于条件可能对环境产生影响(如if (i=a)or if(myfunction())),它们应该按书面形式执行,但我想知道我是否遗漏了编译器可以做的一些优化,这会改变 ifs 的测试顺序. 特别是,如果这种情况没有这样的副作用:

void test(int a)
{
    if (a == 1)
    {
        doSomething1();
    }
    else if (a == 2)
    {
        doSomething1();
    }
    else if (a == 3)
    {
        doSomething1();
    }
    else
    {
        doSomething1();
    }
}
4

5 回答 5

7

是否有任何保证在编译(用于发布)之后,将测试第一个 if,然后是第二个 if,然后是第三个 if(如果条件都不为真,则最后执行 else)。

是的,但不是专门针对您的所有(单线程)代码的 if 语句。

C++ 代码从头到尾自上而下地执行。唯一可能不是这种情况的情况是当您进行异步调用或有多个线程同时调用相同的代码时。

于 2012-05-09T18:23:02.337 回答
6

从 C++03,第 6.4 节选择语句:

1

选择声明:
     if (条件)语句
     if (条件)语句else语句
     switch (条件)语句
[...] 如果选择语句中的子语句是单个语句而不是复合语句,就好像它被重写为包含原始子语句的复合语句。[例子:

  if (x)
     int i;

可以等效地改写为

  if (x) {
      int i;
  }

[...]

6.4.1if声明

1 如果条件 (6.4) 产生true,则执行第一个子语句。如果else选择语句的一部分存在并且条件false为 ,则执行第二个子语句。[...]

从 6.4 1 开始,您的示例代码相当于:

if (cond1) {
    doSomething1();
} else {
    if (cond2) {
        doSomething2();
    } else {
        if (cond3) {
            doSomething3();
        } else {
            doElse();
        }
    }
}

请注意,这并不意味着代码被转换为上述代码,而是两者的行为必须相同。

从 6.4.1 开始,当外部条件为时,将执行内部if语句。如果条件为,则执行第一个分支。虽然标准没有明确说明条件为 时不执行第二个分支,但它强烈暗示省略。iffalsetruetrue

根据§ 1.9 1:

本国际标准中的语义描述定义了一个参数化的非确定性抽象机。本国际标准对一致性实现的结构没有要求。特别是,它们不需要复制或模仿抽象机器的结构。相反,需要符合要求的实现来模拟(仅)抽象机的可观察行为,如下所述。5)

5)该规定有时被称为“好像”规则,因为只要结果是就好像该要求已被遵守,实施可以随意忽略本国际标准的任何要求,只要可以从程序的可观察行为。例如,如果一个实际的实现可以推断出它的值没有被使用并且不会产生影响程序可观察行为的副作用,那么它就不需要评估表达式的一部分。

因此,如果子语句没有副作用,则可以执行部分else​​子语句,并且即使条件结果为 ,结果也会被丢弃true。例如,如果分支预测错误地预测条件将是,则子语句条件可能会在处理器流水线内部分执行。但是,这种影响一定不能引起注意,因此(从您的角度来看)子语句的行为就像 §s 6.4 1 和 6.4.1 1 中所概述的那样。false

于 2012-05-09T18:37:55.197 回答
5

不,唯一可以保证的是,可观察的行为“好像” ifs 是按顺序评估的。条件的评估甚至可以是交错的,cond2 的一部分在 cond1 之前,而 cond1 之后的另一部分已经被评估。另一方面,保证结果将“好像” ifs 已按顺序评估,如果某些条件具有副作用,则如果较早的 ifs 之一为真,则不会发生这些副作用。

关于优化,一定要把最可能的条件放在首位。在实践中,编译器只有在知道移动会改善事情时才会移动代码,所以如果条件或多或少是独立的,并且编译器不能通过折叠它们的一部分来“优化”它们,那么顺序将被保留。除非编译器非常好,并且可以确定您的排序不是最优的(基于分析器输出)。

于 2012-05-09T18:29:17.650 回答
0

是的,条件是按照 if、else if、else 结构的顺序检查的。在给定的条件检查中,可以用括号稍微调整一下。

于 2012-05-09T18:22:52.507 回答
0

除了少数例外,C++ 编译器只允许优化语句,只要其他东西表现得“好像”它正在执行未优化的语句。

重新排序 if/else 塔的语句不会表现得“好像”它没有被重新排序(当然,除非编译器可以证明它会是这样,比如某些检查总是对或错并且没有副作用) .

您绝对可以依赖 if/else 塔的顺序。

于 2012-05-09T18:28:39.583 回答