我想声明一个“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];
}
有没有人知道如何执行此操作?
答案 0 :(得分:40)
GCC功能可以称为“labels as values”。
void *s[3] = {&&s0, &&s1, &&s2};
if (n >= 0 && n <=2)
goto *s[n];
s0:
...
s1:
...
s2:
...
仅适用于GCC!
答案 1 :(得分:17)
goto
需要一个编译时标签。
从这个例子看,你似乎正在实现某种状态机。最常见的是,它们被实现为switch-case结构:
while (!finished) switch (state) {
case s0:
/* ... */
state = newstate;
break;
/* ... */
}
如果您需要它更具动态性,请使用函数指针数组。
答案 2 :(得分:12)
没有直接的方法来存储代码地址以跳转到C. 如何使用开关。
#define jump(x) do{ label=x; goto jump_target; }while(0)
int label=START;
jump_target:
switch(label)
{
case START:
/* ... */
case LABEL_A:
/* ... */
}
您可以找到每个无堆栈解析器/状态机生成器生成的类似代码。 这样的代码不容易理解,除非它是生成代码或你的问题最多 很容易通过状态机描述我建议不要这样做。
答案 3 :(得分:8)
你可以使用函数指针而不是goto吗?
这样你就可以创建一个函数数组来调用和调用相应的函数。
答案 4 :(得分:6)
在简单的标准C中,据我所知,这是不可能的。然而,GCC编译器中有一个扩展documented here,这使得这成为可能。
扩展程序引入了新的运算符&&
,以获取标签的地址,然后可以将其与goto
语句一起使用。
答案 5 :(得分:5)
这就是switch
陈述的用途。
switch (var)
{
case 0:
/* ... */
break;
case 1:
/* ... */
break;
default:
/* ... */
break; /* not necessary here */
}
请注意,编译器不一定会将其转换为跳转表。
如果您真的想自己构建跳转表,可以使用函数指针数组。
答案 6 :(得分:3)
你可能想看看setjmp / longjmp。
答案 7 :(得分:2)
你不能用goto做 - 标签必须是标识符,而不是变量或常量。我不明白为什么你不想在这里使用一个开关 - 它可能会同样有效,如果这是关于你的。
答案 8 :(得分:2)
对于一个简单的答案,而不是强迫编译器做真正的愚蠢的事情,学习良好的编程实践。
答案 9 :(得分:1)
标记生成器?这看起来像是为什么制造了gperf。不,真的,看看它。
答案 10 :(得分:1)
优化编译器(包括GCC)会将switch语句编译成跳转表(使switch语句与您尝试构建的语句完全一样快)如果满足以下条件:
您的开关案例(州号)从零开始。
您的开关箱严格增加。
切换案例中不会跳过任何整数。
有足够多的情况下跳转表实际上更快(在检查每个案例处理switch语句的方法中,有几十个比较并且比跳转表更快。)
这样做的好处是允许您使用标准C编写代码,而不是依赖编译器扩展。它在GCC中的工作速度同样快。它在大多数优化编译器中的工作速度也一样快(我知道英特尔编译器会这样做;不确定微软的东西)。它会在任何编译器上运行,虽然速度较慢。