1
19
一 跳转表 是用于 转移控制 去另一个地方。goto、continue和break类似,只是它们总是转移到特定的位置,而不是从多个位置转移一个可能性。特别是,此控制流与函数调用不同。(维基百科关于 branch tables 是相关的。) 一 switch语句 是如何在C/C++中编写跳转表的。在这种常见的情况下,只提供有限的形式(只能打开整型),以使实现更容易和更快。(对于整型,如何有效地实现跳转表的研究比一般情况下的要多得多。)一个经典的例子是 Duff's Device . 然而, 跳台的全部功能通常不需要 例如,当每个案例都有一个中断语句时。这些“有限跳台”是 不同花样 它只利用了跳跃表的良好学习效率,并且在每个“动作”都独立于其他动作时很常见。 跳转表的实际实现形式不同,主要是索引到索引的映射方式不同。这种映射就是“字典”和“哈希表”这样的术语出现的地方,这些技术可以独立于跳转表使用。说一些代码“使用跳转表”本身并不意味着您有O(1)查找。 编译器可以自由地为每个switch语句选择查找方法,并且不能保证您会得到一个特定的实现;但是,应考虑编译器选项,如速度优化和大小优化。 你应该 研究数据结构 来处理他们强加的不同的复杂性需求。简而言之,如果“dictionary”的意思是平衡二叉树,那么它是O(log n);哈希表取决于它的哈希函数和冲突策略。在switch语句的特定情况下,由于编译器具有完整的信息,因此它可以生成 perfect hash function 这意味着o(1)查找。但是,不要仅仅看整个算法的复杂性就迷路了:它隐藏了重要的因素。 |
2
4
跳转表基本上是指向代码块的指针数组,用于处理switch语句中的各种情况。它最有可能是在您的事例密集时生成的(即,对于一个范围内的每个可能值都有一个事例)。例如,给出如下语句:
它可以生成大致相当于以下内容的代码:
这很复杂。典型的哈希表也大致有O(k) 预期 复杂性,尽管最坏的情况通常是O(N)。跳转表通常更快,但通常只在表非常密集的情况下使用,而哈希表/字典即使在情况非常稀疏的情况下也能很好地工作。 |
3
3
假设您有一系列的过程:
假设您接受来自用户的输入字符(来自a-z),并运行fc:
理想情况下,这将被以下内容取代:
当然,你可以把桌子调大,这样就不需要进行范围检查了。 编译器可以对任意代码执行此操作,而不一定只执行函数调用,并且可以通过存储要跳转到的地址(本质上是goto)来执行此操作。C不直接支持任何类型的计算goto(索引到表中或其他类型),但是它的CPU指令非常简单。 |
4
2
编译switch语句可以采用多种形式,具体取决于具体情况。如果两个箱子靠得很近,那就不用费心了:用跳台。如果案例相距很远,请使用if(case==value)或使用map。或者编译器可以使用一个组合:由跳转表范围的if检查确定的跳转表孤岛。 |
5
1
跳转表是一个简单的函数指针数组,您可以大致这样描述跳转表:
据我所知,这与类似于so的case语句一起使用:每个条件case将是该数组的索引,例如:
每种情况下,转换成简单的函数[A]。这意味着访问函数[9]和访问函数[1]一样快。给你你你提到的O(1)时间。 显然,如果您有case 1和case 4907,这将不是一个好方法,并且您提到的哈希表/字典方法可能会起作用。 |
6
0
进一步阐述 Jerry's answer 及其他 鉴于:
您可以有如下内容:
编译器可以使用跳转表进行索引
编译器可以在创建具有
但是如果你编写了函数,并滚动了你自己的跳转表,
注意,在许多情况下,编译器将生成一个保护来检查
有趣的是,对于少数情况,在不同的编译器标志(依赖于编译器)下,
或者它可以优化这个(简单的测试是一条指令),以:
最好的建议是查看生成的程序集,看看编译器对您的体系结构上的代码做了什么,如果存在跳转表,Linux/Intel上的G++将生成类似以下内容的程序集
(
注意我必须去5
注意,小洞将在跳台上做
将生成以下程序集代码( //注释是我的 ):
|
ZenBa2 · getopt未更改值C 2 年前 |
Waeez · 条件未满足php仍在运行 6 年前 |
Catz · 正在尝试打印正确数量的“*”以代替数值 6 年前 |
privilegedMale · switch语句中的扫描仪问题 6 年前 |
rasilvap · 具有多个参数的开关箱 6 年前 |
RudziankoÅ · 不可能的类型切换情况:不能有动态类型 6 年前 |
Leo Thomas · 循环case语句而不退出shell脚本 6 年前 |