我一直在努力学习跳桌是什么,而我却无法理解某些东西。从我看过的很多例子来看,它们似乎已经归结为这个,或者至少这是它的一个版本:
void func1() {};
void func2() {};
void func3() {};
int main()
{
void(*jumpTo[3])(void) = { func1, func2, func3 };
jumpTo[1]();
return 0;
}
这些似乎是一个函数指针数组,它们由某个值/位置索引。那么跳转表只是索引一个函数指针数组吗?我对此非常好奇,因为我看到很多人都说switch语句经常被编译成跳转表作为性能指标。根据我的理解,通过以这种方式跳转到函数,它涉及指针取消引用和函数调用。 我认为这两者对表现来说并不是那么好。
该网站的另一个答案是,通过这种方式“你正在添加一个switch语句不一定具有的函数调用开销”。编译成跳转表的开关如何避免函数调用?
此外,一个高度投票的答案说:“跳转表可以是函数指针数组或机器代码跳转指令数组。” 您将如何跳转到机器代码指令而不是取消引用指针?这更快吗?
在上面的例子中,两者之间的区别是指针不必被取消引用,因为它可以静态绑定吗?而不是在运行时传入一个随机数作为索引?
感谢。
答案 0 :(得分:3)
跳转表和函数表基本相同 - 地址数组。跳转表包含public function insertsingle()
{
$string = "INSERT INTO academic (name,username,pw) VALUES (?, ?, ?)";
$stmt = mysqli_prepare($this->con, $string);
$stmt->bind_param("sss", $this->getName(), $this->getUserName(), $this->getPassword());
$rsint = $stmt->execute();
return $rsint;
}
- 目标的地址。
两者之间的唯一区别是跳跃是如何进行的。当一个函数被调用时,返回地址被压入堆栈,所以当函数终止时它可以返回。
这是一个跳转表的例子:
goto
这编译为:
#include <stdio.h>
int main(int argc, char *argv[])
{
switch (argc)
{
case 1:
printf("You provided no arguments.");
break;
case 2:
printf("You provided one argument.");
break;
case 3:
printf("You provided two arguments.");
break;
case 4:
printf("You provided three arguments.");
break;
case 5:
printf("You provided four arguments.");
break;
case 6:
printf("You provided five arguments.");
break;
default:
printf("You provided %d arguments.", argc-1);
break;
}
return 0;
}
答案 1 :(得分:1)
主要区别在于对于跳转表,您通常可以使用相对于程序计数器的寻址,这样表不需要任何重定位,并且可以存在.text
部分(或其他部分,不可写和共享)。这是因为典型的跳转表仅在同一目标文件中的极少数位置使用,并且汇编器已知所有偏移量。
如果你有一个函数指针数组,那么你需要生成真正的指针,这需要某种形式的重定位。
第二种可能性,即跳转指令数组,并不仅限于跳转指令本身。重要的是所有目标指令序列(除了最后一个)具有相同的长度,因此可以容易地计算跳转到的偏移量。这样,不需要跳转表,但它确实需要精确的指令宽度(和计数)信息,这在大多数目标上很难保证(RISC架构在加载常量时可能难以预测有效的指令数量) )。这意味着在实践中,这种方法仅限于针对目标的非常特定的跳转指令形式。
答案 2 :(得分:1)
void(*jumpTo[3])(void) = { func1, func2, func3 };
jumpTo[1]();
整体上是使用跳转表 - 而不仅仅是函数指针的取消引用。
C也提供其他机制 - 例如,交换机案例通常被编译成跳转表,特别是如果案例值具有窄范围,并且两者之间的间隙很小。 GCC提供的另一种机制是use of goto
labels as pointer values with computed goto
。