任何编译器都没有将大型交换机块转换为二叉树?

时间:2014-06-10 10:47:06

标签: c++ compiler-construction compiler-optimization

我已经读过现代C ++编译器将大switch块转换为二进制树以便在运行时更快地查找,这是否适用于所有现代C ++编译器?我主要使用英特尔C ++编译器和G ++。

4 个答案:

答案 0 :(得分:5)

如果您的case值彼此接近,那么最有效的方法是跳转表,这通常是所有编译器的目标。如果值很稀疏,那么编译器通常会使用" binary-if-tree"。

最佳解决方案:不要考虑它。假设switch速度相当快。其他一切都闻起来像是过早优化。如果您确实遇到switch是程序的瓶颈,那么您只能通过查看生成的目标代码来了解生成的内容。

如果您只在每种情况下分配一个变量,编译器甚至可能生成完全不同的东西,如条件移动。所以,如果不看生成的装配,你永远不会知道。

如果你有很多稀疏值,那么使用哈希表可能比switch更快,因为与{34}的O(1)相比,它是O(log n) -if树"

答案 1 :(得分:2)

当然,即使是GCC,例如:

int test(int x) {
  switch (x) {
   case 0:
    return 2;
    case 1:
    return 7;
    case 3:
    return 11;
    case 4:
    return 2;
    case 5:
    return 133;
    case 6:
    return 500;
  }
}
在定位x64时,

在我测试的所有GCC版本上都变成了跳转表。 (甚至在-O0上)

“将大switch块转换为二进制树以便更快地查找”也具有误导性,确定它比线性if / else链更快(除非第一项非常极端比后来更有可能),但跳转表可能更快。

另一方面,跳转表不能很好地处理稀疏情况,除非你使用special techniques,但据我所知,还没有真正完成(但是?)。此外,CPU通常预测间接分支不太好 - 通常只是预测它总是与上次一样。

他们实际上只有不同的性能特征,switch的所有可能实现都没有赢。这取决于。

答案 2 :(得分:2)

我建议测量执行时间。如果您的代码需要优化,那么您可以做出明智的决定。

你提到这是你的用例:

  

我有一个带有> 400长整数的开关,它们是CRC-64校验和   ISO 639语言名称,我使用它来快速查找ISO语言   名。

通常您会使用其中一种STL数据类型。例如,在您的情况下,std::mapstd::unordered_set值得一试。 std::map使用红色/黑色树,std::unordered_set使用哈希表。

答案 3 :(得分:2)

过去曾在编译器上工作过......

首先处理switch语句的正常方法是排序 案例值,然后寻找紧凑的块,其中有 相邻或接近相邻的值。这样的块将是 分离出来,用跳台处理;一个数组 目标地址,由值索引(减去值的值) 表的第一个元素)。任何剩余的值都将是 使用硬编码二进制搜索进行检查。

这是大约25年前的标准程序。我会假设 如果它从那时起发生了变化,那是因为有人有 想出一个更好的解决方案。 (数学上,它是 很容易证明你无法在中获得更好的大O. 一般情况。)例如,现代编译器可能会使用 分析器信息,以确定哪些情况更有可能, 如果它们更有可能,请先测试它们。