C++ c开关和跳转表

C++ c开关和跳转表,c++,switch-statement,jump-table,C++,Switch Statement,Jump Table,据我所知,c/c++中的switch语句有时会编译成跳转表。 我的问题是,有什么经验法则可以保证这一点吗 就我而言,我正在做这样的事情: enum myenum{ MY_CASE0= 0, MY_CASE0= 1, . . . }; switch(foo) { case MY_CASE0: //do stuff break; case MY_CASE1: //do stuff break; . . . } 我按订单把从1到n的所有箱子都包括在内。可以安全地假设

据我所知,c/c++中的switch语句有时会编译成跳转表。 我的问题是,有什么经验法则可以保证这一点吗

就我而言,我正在做这样的事情:

enum myenum{
MY_CASE0= 0,
MY_CASE0= 1, 
.
.
.
};

switch(foo)
{
  case MY_CASE0:
  //do stuff
  break;
  case MY_CASE1:
  //do stuff
  break;
 .
 .
 .
}
我按订单把从1到n的所有箱子都包括在内。可以安全地假设它将编译为跳转表吗?
原始代码是一个冗长而混乱的
if-else
语句,因此至少我获得了一些可读性。

一个好的编译器可以并且将在跳转表、链接if/else或组合中进行选择。一个设计拙劣的编译器可能不会做出这样的选择——甚至可能为开关块生成非常糟糕的代码。但是任何好的编译器都应该为开关块生成高效的代码。T

这里的主要决定因素是,当数字相距较远时,编译器可能会选择if/else[并且不会很小地(例如,除以2、4、8、16、256等)更改为更接近的值],例如

 switch(x)
 {
    case 1:
     ...
    case 4912:
     ...
    case 11211:
     ...
    case 19102:
     ...
 }
需要至少19102*2字节的跳转表

另一方面,如果数字很接近,编译器通常会使用跳转表

即使是
if/else
类型的设计,它通常也会进行“二进制搜索”——如果我们以上述示例为例:

 if (x <= 4912)
 {
     if (x == 1)
     {
        ....
     }
     else if (x == 4912)
     {
         .... 
     }
 } else {
     if (x == 11211)
     {
         ....
     }
     else if (x == 19102)
     {
         ...
     }
 }
如果将某些值放在if-else链的开头,这可能会稍微好一些,但前提是您可以在运行代码之前确定最常见的值


如果性能对您的案例至关重要,那么您需要对这两个备选方案进行基准测试。但我的猜测是,仅仅将代码作为开关来编写将使代码更加清晰,同时运行速度至少与开关一样快,如果不是更快的话

编译器当然可以将任何C/C++开关转换为跳转表,但编译器会这样做以提高效率。问问自己,如果我正在编写一个编译器,而我刚刚为switch/case语句构建了一个解析树,我会怎么做?我研究过编译器的设计和构造,下面是一些决定

如何帮助编译器决定实现跳转表:

  • 大小写值是小整数(0,1,2,3,…)
  • 大小写值在一个紧凑的范围内(几个孔,请记住默认值是一个选项)
  • 有足够的实例使优化值得(>N,检查编译器源代码以找到常量)
  • 如果范围很小,聪明的编译器可能会在跳转表索引中减去/添加一个常量(例如:1000、1001、1002、1003、1004、1005等)
  • 避免失误和控制权转移(转到,继续)
  • 每个案例结束时只有一次中断
虽然编译器之间的机制可能不同,但编译器本质上是在创建未命名的函数(嗯,可能不是函数,因为编译器可能使用跳入代码块和跳出代码块,或者可能很聪明,使用jsr和return)

获取跳转表的特定方法是编写跳转表。它是指向函数的指针数组,按所需的值进行索引

怎么做

为函数指针定义一个typedef

类型定义无效(*FunkPtr)(双a1,双a2)

当然,您已经定义了函数{0..n},因此编译器可以找到要调用的函数的地址


我将把调用函数指针和边界检查留给读者作为练习。

1)这很可能取决于编译器。你用哪一种?2) 你为什么在乎?你应该相信你的编译器会对你所写的代码做到最好。跳转表可能不是所有情况下的最佳选择。没有完全回答你的问题,但你可能对@BoBTFish:谢谢你的指点感兴趣,谢谢。@BoBTFish谢谢,如果我有时间的话,这本书看起来不错(:你为什么在意?编译器编写者可能比你更了解目标硬件,而且编译器通常会生成尽可能最好的代码,无论是跳转表、链式测试还是其他任何代码。为什么?跳转表很容易编写。如果你想写,就写一个。开关/大小写是清楚的,对于少数情况,它可以这只是一些cmp/jmp指令。一般来说,请相信您的编译器。
if (x == first value) ... 
else if (x == second value) ... 
else if (x == third value) ... 
..
else if (x == nth value) ... 
else ... 
FunkPtr JumpTable[] = {
    function_name_0,
    function_name_1,
    function_name_2,
    ...
    function_name_n
};