对于较大的switch case语句,最好将它们分开吗?

时间:2012-06-21 04:16:18

标签: c performance

快速提问。例如,使用一些大约1000个选项的大型案例:哪种是“最佳”方法?我并不是特意想要直接获得更快的结果。

switch (foo) {
    case 0: 
        // code ...
        break; 

    // One, two, skip a few...

    case 1000:
        // code ...
}

或分裂可能结果的东西,以便它可以快速找到正确的案例陈述。类似的也是:

if (foo < 101) {
    if (foo < 51)
        switch (foo) {}
    else
        switch (foo) {}
} else if (foo > 100 && foo < 201) {

// skipped for convenience 

} else if (foo > 900) {
    if (foo < 951)
        switch (foo) {}
    else
        switch (foo) {}
}

我想第二种方法对于较大的数字要快得多,但第一种方法似乎也可以轻松通过它,因为它不是经常检查语句。这些方法中有一种不赞成还是有更好的方法?这是针对C的,但我有兴趣知道它与其他语言的一致性。谢谢!

5 个答案:

答案 0 :(得分:9)

如果编译器使用跳转表实现它们,那么

switch语句可以非常快,但这只能在cases的特殊序列上实现,并且可能不实际,它实际上取决于可能cases -fno-jump-tables 1}}。编译器可能会也可能不会使用跳转表,我确实发现这个http://blog.jauu.net/2010/06/15/GCC-generated-Switch-Jump-Tables/很有意思。

JUMP表格可以非常快,因为它只计算偏移量并跳转到适当的地址。

GCC确实有fun_table[indice]();,它会完全禁用它。

有时你可以使用函数指针数组和特殊索引来构建自己的跳转表,这可以使你的代码非常快,但在所有情况下都不实用,想象你有一个开关,在每种情况下你都会调用一个函数,你可以构建一个函数指针数组,设置一个默认函数只是为了安全,然后你只需要{{1}}而不是一个开关我为自己的虚拟机做了一次。

答案 1 :(得分:1)

我认为switch语句通常被解释为底层汇编语言中的goto,这将使第一种方法显着加快。

这似乎支持这一点,虽然它不完全证明:http://en.wikibooks.org/wiki/Optimizing_C%2B%2B/Writing_efficient_code/Performance_improving_features#Case_values_of_switch_statements

答案 2 :(得分:1)

我认为switch语句更好,至少从代码可读性的角度来看(并且可能从速度的角度来看,因为它只选择一个块来运行,因为它必须评估多个条件,如第二个例子中所示)。 )

答案 3 :(得分:1)

不推荐任何功能应该适用于大约1.5个屏幕,因此这样一个巨大的开关声明将不适合这个账单。为了解决这个问题,有一个dispatch表。你要做的就是索引数组以找到适当的函数来调用。

答案 4 :(得分:0)

我发布此内容仅供参考,因为samy.vilar已经为函数数组提供了最优雅的解决方案。如果您使用GCC,它可以理解案例范围。此代码最终将以与第二种解决方案非常相似的方式运行,从而产生一些二叉树代码路径(假设没有编译器优化)。

int             nested_switch(int i)
{
  switch (i) {
    /* i is in the 1..10 range */
  case 1 .. 10:
    switch (i) {
      /* i is in the 0..5 range */
    case 1 .. 5:
      switch (i) {
      case 1:
        break;
      case 2:
        break;
      ...
      case 5:
        break;
      }
    case 5 .. 10:
      switch (i) {
      case 6:
        break;
      case 7:
        break;
      ...
      case 10:
        break;
      }
    }
    /* i is in the 11..20 range */
  case 11 .. 20:
    switch (i) {
      ...
    }
  }

  return 0;
}