C++开关语句评估



假设我们有以下代码:

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

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

执行起来更快的是什么:开关情况,还是带有||运算符的if?

澄清:如果满足任何条件,我希望执行doSomething。我还知道,"G"病例将发生在99%的病例中。如果我把它放在列表的首位,我能假设它会被作为第一个进行比较吗?

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

它将立即跳转执行doSomething()

执行起来更快的是什么:开关情况,还是带有||运算符的if?

我认为这与任何像样的现代c++编译器都没有任何区别,并且发出的代码应该相当相同。

执行起来更快的是什么:开关情况,还是带有||运算符的if?

转到switch()。如果您有一个设置了小值的枚举或整数,switch()通常会创建一个跳转表。

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']();
    }
}

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

以下是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条目的跳转表,你就无法更快地编写任何东西,这会对缓存位置和耗尽产生影响。

如果满足第一个条件(currentChar=='G'(,则如下案例也进行了评估,或者程序直接跳到doSomething((?

它会失败,直到找到break或到达终点。

执行起来更快的是什么:开关情况,还是带有||运算符的if?

您应该担心代码的可读性和可支持性,所以使用对您来说更可读的代码。然后,如果您对程序速度有问题,请进行优化。

为了可读性——当然这是主观的,但使用switch,您可以获得更少的详细代码,因为您不必多次重复变量名:

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

所以在这种情况下我更愿意转换。

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

这使得如果currentCharGTM;rn,则调用doSomething()。使用switch比使用普通的if更快,因为switch语句通常被优化为跳转表。这就是为什么开关必须在恒定的积分值上操作。

不能保证开关情况下的检查顺序。如果表达式没有副作用,也不能保证||的执行顺序
基本上,如果唯一的区别是时间,那么基于"好像"规则,c++不会保证任何东西的顺序。

如果满足第一个条件(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语句的最后一条语句。有关switch语句的工作示例,请参阅此链接。

执行起来更快的是什么:开关情况,还是带有||运算符的if?

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

编辑以供澄清

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

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

我还知道,"G"病例将发生在99%的病例中。如果我把它放在列表的首位,我能假设它会被作为第一个进行比较吗?

剩下的病例将不予检查。

相关内容

  • 没有找到相关文章

最新更新