C++ 如何将转到标签存储在数组中,然后跳转到它们?
我想声明一个“jumplabels”数组 然后我想跳到这个数组中的“jumplabel” 但我不知道怎么做 它应该类似于以下代码:C++ 如何将转到标签存储在数组中,然后跳转到它们?,c++,c,goto,jump-table,C++,C,Goto,Jump Table,我想声明一个“jumplabels”数组 然后我想跳到这个数组中的“jumplabel” 但我不知道怎么做 它应该类似于以下代码: function() { "gotolabel" s[3]; s[0] = s0; s[1] = s1; s[2] = s2; s0: .... goto s[v]; s1: .... goto s[v]; s2: .... goto s[v]; } 有人
function()
{
"gotolabel" s[3];
s[0] = s0;
s[1] = s1;
s[2] = s2;
s0:
....
goto s[v];
s1:
....
goto s[v];
s2:
....
goto s[v];
}
有人知道如何执行此操作吗?在C中没有直接的方法来存储要跳转到的代码地址。 使用开关怎么样
#define jump(x) do{ label=x; goto jump_target; }while(0)
int label=START;
jump_target:
switch(label)
{
case START:
/* ... */
case LABEL_A:
/* ... */
}
您可以找到每个无堆栈解析器/状态机生成器生成的类似代码。
这样的代码不容易理解,所以除非它是生成的代码或者您的问题最严重
很容易用状态机描述,我建议不要这样做。你能用函数指针代替goto吗
这样,您就可以创建一个函数数组来调用相应的函数。在普通标准C中,据我所知,这是不可能的。然而,GCC编译器中有一个扩展,使这成为可能
扩展引入了新的操作符
&&
,以获取标签的地址,然后可以与goto
语句一起使用。goto
需要一个编译时标签
从这个例子来看,您似乎正在实现某种状态机。最常见的是,它们被实现为一个开关盒构造:
while (!finished) switch (state) {
case s0:
/* ... */
state = newstate;
break;
/* ... */
}
如果您需要它更具动态性,请使用函数指针数组。这就是
switch
语句的用途
switch (var)
{
case 0:
/* ... */
break;
case 1:
/* ... */
break;
default:
/* ... */
break; /* not necessary here */
}
请注意,编译器不一定会将其转换为跳转表
如果你真的想自己构建跳转表,你可以使用函数指针数组。你不能用goto来实现-标签必须是标识符,而不是变量或常量。我不明白你为什么不想在这里使用开关——如果这正是你所关心的,它可能同样有效。简单的回答是,与其强迫编译器做真正愚蠢的事情,不如学习好的编程实践。GCC特性被称为“”,这是可能的
void*s[3]={&&s0,&&s1,&&s2};
如果(n>=0&&n您可能需要查看setjmp/longjmp。标记化器?这看起来像是gperf的用途。不,真的,看看它。优化编译器(包括GCC)会将switch语句编译成跳转表(使switch语句的速度与您试图构造的东西一样快)如果满足以下条件:
您的开关箱(状态编号)从零开始
你的开关箱在不断增加
在开关的情况下,不会跳过任何整数
跳转表实际上要快的情况已经足够多了(处理switch语句的checking-each-case方法中的几十个compare和goto实际上要比跳转表快。)
这样做的好处是,您可以用标准C编写代码,而不必依赖编译器扩展。它在GCC中的运行速度与在大多数优化编译器中的运行速度一样快(我知道英特尔编译器可以做到这一点;但对微软的东西不太确定)。它在任何编译器上都能工作,尽管速度较慢。很有趣,我不知道。谢谢。如果这是一个家庭作业,我不建议你这样做-你的教授不会喜欢的。不,不是,我十七岁了,正在试着写一个简单、快速的标记器。我想过用这种方式来加速它。你在下面的评论中提到,可能有2个**16个案例。这是正常的吗?如果是这样,它会极大地改变问题。@你知道:你确定这就是需要加快的地方吗?你分析过你的代码吗?2^16个案例,你想把它作为一个单一的代码块来维护……当你想修改任何东西时,你会在更早的时候遇到麻烦。代码将不完整ainable,每个case加上label和goto只需要几行代码,你就在谈论一个250 KLOC的函数。从可以工作的代码开始,然后根据需要进行测量和优化。在不知道上下文的情况下,你怎么能判断这是“真正愚蠢的东西”?盲目地遵循规则(例如“goto是邪恶的”)这对初学者很好。有经验的程序员知道在哪里破例。经过考虑,有经验的程序员不太可能会问这样的问题,但这是不礼貌的预先判断。这只是一个简单的例子……在我的选项中,如果我有2^16个案例,开关会变慢?不是吗?@youllknow:通常好的编译器会优化一个密集的为您切换到跳转表。因此,不,切换不一定慢。我知道它可以通过函数指针实现。但这会很慢,因为我必须经常调用一个函数。我认为调用开销会很大!@youllknow:上面评论中的“我认为”这几个字告诉我,您真的有陷入陷阱的危险“过早优化”。第一个目标应该是从明确的“工作”开始"解决方案,然后根据需要优化它。考虑一下:只有1编译器有这个特性作为扩展,但是,每一个C/C++编译器都使用状态机。如果这是解决这个问题的最佳方法,为什么每个编译器都没有这个特性?@ Richard Corden:那么你认为速度改进很低吗?我想到了。函数指针数组也是如此。问题是函数会被频繁调用,但它们只做很少的事情。因此我认为调用函数可能比函数所做的更昂贵。我可以用函数指针来实现我的问题,但我认为我可以用“goto方法”来加速.你的看法是什么?@youllknow:函数调用非常便宜:它不比goto昂贵多少,问题也少得多。记住,编译器在优化方面总是比你强。@youllknow:会有性能上的差异,但你需要记住“清晰性”和“性能”之间的权衡。如果是我,我的第一个“性能”调整就是看看我能不能使用一些模板+内联函数的组合
void *s[3] = {&&s0, &&s1, &&s2};
if (n >= 0 && n <=2)
goto *s[n];
s0:
...
s1:
...
s2:
...