2

快速提问。例如,使用大约 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 的,但我有兴趣了解它与其他语言的一致性。谢谢!

4

5 回答 5

9

switch如果编译器使用跳转表来实现语句,它们的速度可能会非常快,但这仅在 的特殊序列上才有可能cases,并且可能不实用,它实际上取决于可能的cases. 编译器可能使用也可能不使用跳转表,我确实发现了这个http://blog.jauu.net/2010/06/15/GCC-generated-Switch-Jump-Tables/这很有趣。

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

GCC 确实有-fno-jump-tables完全禁用它。

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

于 2012-06-21T04:22:30.817 回答
1

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

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

于 2012-06-21T04:20:01.177 回答
1

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

于 2012-06-21T04:22:11.167 回答
0

是不是不建议任何功能应该适合大约 1.5 个屏幕,所以这么大的 switch 语句不适合这个账单。为了克服这个问题,有一个调度表。您所要做的就是对数组进行索引以找到要调用的适当函数。

于 2012-06-21T04:27:00.477 回答
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;
}
于 2012-06-21T11:40:19.773 回答