30

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

因此我问自己:

  • (如何)在运行时速度、编译时优化和一般编译方面有什么switch不同?if-elseif-elseif我这里主要说的是MSVC。
4

2 回答 2

40

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

于 2010-04-07T22:19:19.433 回答
8

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

编译 switch 语句的最基本(未优化)方法是将其视为if ... else 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:

这种方法更快的一个原因是条件句中的代码更小(因此,如果条件被错误预测,指令缓存惩罚会更小)。此外,“失败”的情况变得更容易实现(编译器放弃了该goto end语句)。

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

提醒一句:嵌套跳转表很难生成,一些编译器甚至拒绝尝试创建一个。出于这个原因,如果最大限度优化的代码对您很重要,请避免将 a 嵌套switch在另一个内部switch(我不是 100% 确定 MSVC 特别是如何处理嵌套switch的 es,但编译器手册应该告诉您)。

于 2010-07-19T15:16:17.460 回答