8

可能重复:
为什么切换/案例而不是如果/否则如果?

我想了解编译器如何将switch() case:C 中的语句翻译成汇编器操作码。

具体来说,我有兴趣了解一系列if then else分支的区别。

性能比较是主要话题。

关于词汇的几句话:我熟悉汇编程序的主要概念,很久以前就为更简单的系统编写过汇编程序,但现在肯定对 x86 汇编程序语义一无所知。所以直接汇编输出将没有用。伪代码更受欢迎。

4

4 回答 4

6

编译器可以决定将其实现为等效的if/else if语句系列,也可以决定使用分支表对其进行优化。这取决于几个参数,例如分支数和包含您检查的所有值的最小范围的大小。

更新:我记得在某处读到过,除非有至少 4 个或更多开关案例,否则编译器通常不会费心创建分支表;Stephane Rouberol 在下面的信息性评论专门记录了如何为 GCC 配置此阈值。

于 2012-09-21T12:58:09.523 回答
6

根据编译器中的各种启发式方法,生成的代码最终可能只是一个简单的“if else if”语句链。在某些情况下,case空间较小时,编译器可以做一个跳转表,例如:

switch (foo) {
case 0:
    a();
case 1:
    b();
case 2:
    c();
case 3:
    d();
default:
    e();
}

可以翻译成类似的东西:

if (foo < 0 || foo > 3) goto label_default;
else goto internal_jump_table[foo];

internal_jump_table = { label_0, label_1, label_2, label_3 };
label_0: a();
label_1: b();
label_2: c();
label_3: d();
label_default: e();

还有其他可以做的优化。编译器可以构建 if 语句的层次结构来二进制搜索正确的值,而不是检查相等性。或者你可能有一堆适合跳转表的值和一些完成正常搜索的异常值。或者也许只是两个跳表。

于 2012-09-21T13:02:00.540 回答
2

共同的反应总是“取决于”。性能可能取决于平台/CPU 类型、编译器、编译器选项等。

我确实认为,在适当的情况下,switch()构造将具有复杂性 log(n),其中 n 是case:语句的数量。这是通过“二分搜索”实现的。

这个页面有很多细节(专注于微软的编译器,但我认为一般的想法适用)。

于 2012-09-21T13:01:07.870 回答
1

考虑“足够大”的数量switch cases(足以让编译器选择生成分支表而不是简单的if / else if):

  • switch-case 将有恒定时间 (O(1)) 访问要执行的正确代码块,

  • 而一系列if/else if语句将具有线性时间(O(n),其中n是评估(if语句)的条件数,因为n> =“足够大”)

更新:当然这些考虑没有考虑编译器优化!

于 2012-09-21T13:17:23.570 回答