【问题标题】:C++ switch statement evaluationC++ switch 语句求值
【发布时间】:2016-10-27 03:36:59
【问题描述】:

假设我们有以下代码:

switch (currentChar) {
    case 'G':
    case 'T':                   
    case 'M':
    case ';':                       
    case '\r':                      
    case '\n':  
        doSomething();      
        break;
}

如果满足第一个条件(currentChar == 'G')是否还比较以下情况,或者程序直接跳转到doSomething()

什么会更快执行:switch-case 或带有|| 运算符的 if?

说明: 如果满足任何条件,我希望执行doSomething。我也知道 99% 的情况都会出现“G”情况。如果我把它放在列表的顶部,我可以假设它会作为第一个进行比较吗?

【问题讨论】:

  • 以下语句也会被评估,直到它们遇到 break; 语句或脱离 switch 语句。
  • 不清楚你在问什么。 case 是常量表达式,是否对这些常量表达式求值并没有什么区别。您是否在询问 currentChar 是否与这些案例值进行比较?你是在问doSomething() 是否被评估?还是你在问别的?
  • 您可以测试每种方式并​​找出自己。一般来说,哪种方式更快问题过于宽泛,因为它们可能取决于许多不同的因素。
  • @hvd 我在问currentChar 是否与这些案例值进行比较。
  • @mactro 好的。所以你知道doSomething() 将被调用,并且你想知道,当currentChar == 'G'currentChar == 'T'currentChar == 'M'currentChar == ';' 等被毫无意义地评估只是为了忽略它们的结果。那正确吗?在这种情况下,你得到的第一个答案(@πάνταῥεῖ's)可能涵盖了它。

标签: c++ if-statement switch-statement conditional


【解决方案1】:

如果满足第一个条件(currentChar == 'G'),是否还会评估以下情况,或者程序直接跳转到 doSomething()?

在您的示例中,它将直接跳转到doSomething()。如果您不想出现这种行为,则需要插入break 语句,如下面的一种情况所示:

switch (currentChar) {
    case 'G': /*things to be done */ break /* This break will take it out of switch*/;
    case 'T':                   
    case 'M':
    case ';':                       
    case '\r':                      
    case '\n':  
        doSomething();      
        break;
}

另外,请注意,在您的示例中,break 不是必需的,因为它是您的 switch 语句的最后一个语句。请参阅this 链接以获取 switch 语句的工作示例。

什么会更快执行:switch-case,或者带有||的if运营商?

假设您使用的是不错的编译器,差异很小,因此可以忽略。请参考this所以链接,以防您需要了解更多细节。

为澄清而编辑

如果满足任何条件,我希望doSomething() 被执行。

是的,根据您的代码,即使只满足其中一个条件,doSomething() 也会被执行。

我也知道 99% 的情况都会出现“G”情况。如果我把它放在列表的顶部,我可以假设它会作为第一个进行比较吗?

不会检查剩余的案例。

【讨论】:

  • 需要中断,但不是为了正确编译。
  • @Slava 抱歉,你能说得更具体点吗?
  • 最好将break 放在最后一个语句中,一方面编译器会忽略这一点,另一方面 - 当您在最后一个标签之后添加另一个标签时,您不会感到意外。 IE没有break太容易出bug了。
【解决方案2】:

关于特定代码风格的性能结果的问题几乎总是浪费时间。

以下是 gcc5.3 在优化通过后如何处理此代码:

test(char):
        cmpb    $59, %dil
        je      .L3      
        jle     .L6       
        cmpb    $77, %dil
        je      .L3
        cmpb    $84, %dil
        je      .L3
        cmpb    $71, %dil
        je      .L3
.L1:
        rep ret
.L6:
        cmpb    $10, %dil
        je      .L3
        cmpb    $13, %dil
        jne     .L1
.L3:
        jmp     doSomething()

如果不创建一个 256 条目的跳转表,我真的认为你不能写得更快,这会在缓存局部性和耗尽方面产生其自身的后果。

【讨论】:

    【解决方案3】:

    不保证在 switch case 中检查的顺序。如果表达式没有副作用,也无法保证 || 的执行顺序。
    基本上,如果唯一的区别是时间,c++ 根据 as-if 规则不保证任何东西的顺序。

    【讨论】:

    • a || b 是短路的,如果a 评估为真,则保证不会评估b(当然,除非你超载它)。 5.15 [expr.log.or]
    • @user975989:正如我所说,如果 a 和 b 没有副作用,as-if 规则允许编译器以产生相同结果的任何方式实现运算符
    【解决方案4】:

    一旦currentChar'G'比较,指令跳转到指令doSomething()。您不能依赖您的案例顺序来“优化”switch

    请注意,比较不一定是顺序的。
    switch 可以实现为例如跳转表:

    void foo_switch(char c)
    {
        switch (c) {
            case '0': bar0(); break;        
            case '1': bar1(); break;        
            case '2': bar2(); break;        
            case '3': bar3(); break;        
        };
    }
    
    void foo_if(char c)
    {
        if (c == '0') {
            bar0();
        } else if (c == '1') {
            bar1();
        } else if (c == '2') {
            bar2();
        } else if (c == '3') {
            bar3();
        }
    }
    
    void foo_table(char c)
    {
        if ('0' <= c && c <= '3') {
            using voidFPtr = void(*)();
            voidFPtr funcs[] = {&bar0, &bar1, &bar2, &bar3};
            funcs[c - '0']();
        }
    }
    

    【讨论】:

    • 您好,“_comparison 不需要顺序。_”是什么意思,您能否提供一个跳转表的基本设计?
    【解决方案5】:
    switch (currentChar) {
        case 'G':
        case 'T':                   
        case 'M':
        case ';':                       
        case '\r':                      
        case '\n':  
            doSomething();      
            break;
    }
    

    如果currentCharGTM;\r\n,这将调用doSomething()。使用switch 比使用简单的if 更快,因为switch 语句通常被优化为跳转表。这就是为什么开关必须在一个恒定的整数值上运行。

    【讨论】:

      【解决方案6】:

      什么会更快执行:switch-case,或者带有||的if运营商?

      您应该担心代码的可读性和可支持性,因此请使用对您而言更具可读性的内容。然后,如果您对程序速度有疑问,请进行优化。

      为了可读性 - 当然这是主观的,但是使用 switch 可以减少冗长的代码,因为您不必多次重复变量名称:

      if( currentChar == 'G' || currentChar == 'B' || currentChar == 'C' )
      

      所以我宁愿在这种情况下切换。

      【讨论】:

        【解决方案7】:

        如果满足第一个条件(currentChar == 'G'),则如下 还评估了案例,还是程序直接跳转到 doSomething()?

        直到找到break 或到达终点。

        【讨论】:

          【解决方案8】:

          什么会更快执行:switch-case,或者带有||的if运营商?

          switch()。如果你有一个枚举或整数的小值集,switch() 通常会创建一个跳转表。

          【讨论】:

            【解决方案9】:

            如果满足第一个条件(currentChar == 'G'),是否还会评估以下情况,或者程序直接跳转到doSomething()

            会立即跳转执行doSomething()

            什么会更快执行:switch-case 或带有|| 运算符的 if?

            我不认为它与任何体面的现代 c++ 编译器有任何区别,并且发出的代码应该几乎相同。

            【讨论】:

            • 检查我给出的答案。我写了一个程序,使用 if 语句更快。
            猜你喜欢
            • 2015-09-21
            • 2021-07-24
            • 2018-01-11
            • 1970-01-01
            • 2010-12-20
            • 2011-11-27
            • 2012-10-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多