Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何将转到标签存储在数组中,然后跳转到它们?_C++_C_Goto_Jump Table - Fatal编程技术网

C++ 如何将转到标签存储在数组中,然后跳转到它们?

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]; } 有人

我想声明一个“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];
}

有人知道如何执行此操作吗?

在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:
...