C++ switch如何在visualc++;它的优化和速度有多快?

C++ switch如何在visualc++;它的优化和速度有多快?,c++,visual-c++,if-statement,switch-statement,visual-c++-2010,C++,Visual C++,If Statement,Switch Statement,Visual C++ 2010,当我发现我只能在C++的switch语句中使用数值时,我认为它和一堆if-else语句之间肯定有更深的区别 因此我问自己: (在运行速度、编译时优化和一般编译方面,switch与if-elseif-elseif有何不同?我这里主要讲的是MSVC 一个开关通常被编译到一个跳转表(一次比较以找出要运行的代码),或者如果不可能,编译器仍然可以对比较进行重新排序,以便在值之间执行二进制搜索(log N比较)。if-else链是一个线性搜索(尽管,我认为,如果所有相关值都是编译时整数常量,编译器原则上可

当我发现我只能在C++的
switch
语句中使用数值时,我认为它和一堆
if-else
语句之间肯定有更深的区别

因此我问自己:

  • (在运行速度、编译时优化和一般编译方面,
    switch
    if-elseif-elseif
    有何不同?我这里主要讲的是MSVC

一个开关通常被编译到一个跳转表(一次比较以找出要运行的代码),或者如果不可能,编译器仍然可以对比较进行重新排序,以便在值之间执行二进制搜索(log N比较)。if-else链是一个线性搜索(尽管,我认为,如果所有相关值都是编译时整数常量,编译器原则上可以执行类似的优化)

Switch语句通常是编译器优化的常见来源。也就是说,如何处理它们取决于您在编译器上使用的优化设置

编译switch语句最基本(未优化)的方法是将其视为一系列
if。。。否则,如果…
语句。编译器优化交换机的常用方法是将其转换为如下所示的:

if (condition1) goto label1;
if (condition2) goto label2;
if (condition3) goto label3;
else            goto default;
label1:
  <<<code from first `case statement`>>>
  goto end;
label2:
  <<<code from first `case statement`>>>
  goto end;
label3:
  <<<code from first `case statement`>>>
  goto end;
default:
  <<<code from `default` case>>>
  goto end;
end:
if(条件1)转到label1;
如果(条件2)转到标签2;
如果(条件3)转到标签3;
否则就要违约;
标签1:

转到终点;
标签2:

转到终点;
标签3:

转到终点;
违约:
<默认情况下的代码>
转到终点;
完:
此方法速度更快的一个原因是,条件中的代码更小(因此,如果条件被错误预测,则指令缓存惩罚更小)。此外,“fall-through”的情况变得更容易实现(编译器省略了
goto-end
语句)

编译器可以通过创建一个指针数组(指向由标签标记的位置)并使用要打开的值作为该数组的索引,进一步优化跳转表。这将消除代码中几乎所有的条件(除了验证您正在打开的值是否与您的一个案例匹配所需的条件)


注意:嵌套跳转表很难生成,一些编译器甚至拒绝尝试创建一个。因此,如果最大限度地优化代码对您很重要,请避免将
开关
嵌套在另一个
开关
中(我不能100%确定MSVC特别是如何处理嵌套的
开关
es,但编译器手册应该告诉您)。

+1是一个很好的答案。我还将利用这个机会贬低if-then-elseif链。不止一个“else if”是DDD(设计缺陷障碍)的标记。这里是VisualC++的一个标记。如果这是优化的,而不是可以优化的,那就好了。如果案例是/可以排序的,跳转表是否不仅仅和二进制搜索一样好?@Opux跳转表更快:一次查找vs
logn
比较。但是,您需要访问内存,这可能会使它在运行时间上变慢注意:我没有提到与if-else树相关的交换机性能的任何具体数字,因为优化的好处在很大程度上取决于代码。告诉您从优化中得到了多大改进的唯一真正方法是以两种方式编写代码,并测量每种方式运行所需的时间。给定的代码不是跳转表。就这一点而言,它根本不代表任何表格。然而,维基百科的链接确实提供了正确的例子。