首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C89计算goto (再次)如何

C89计算goto (再次)如何
EN

Stack Overflow用户
提问于 2017-05-07 21:56:23
回答 2查看 545关注 0票数 2

我需要编写一个自动机,我碰巧遇到了对计算goto的旧需求(ala fortran4 :)

我需要在一个可移植的ansi-C中进行编码。

我想远离“不要这么做”,远离longjmp/setjmp,远离嵌入式ASM(),远离非ansi-C扩展。

有人知道怎么做吗?

EN

回答 2

Stack Overflow用户

发布于 2017-05-07 22:15:33

正如我在评论中所说的,尽管你恳求不要使用goto以外的任何东西,但标准C没有什么可提供的。

适当地设计您的状态,并将指向它的指针传递给处理程序函数,以便它们进行修改。这样,处理程序就可以设置下一个要调用的函数。如下所示:

代码语言:javascript
复制
struct state;
typedef void state_func(struct state*);
#define NULL_ACTION_ADDRESS (state_func*)0

struct state {
    state_func    *action;
    int            value1;
    int            value2;
};

#define INIT_STATE { initial_action, -1, -1}

state_func initial_action;
state_func handle_a;
state_func handle_b;

int main(void) {
    struct state s = INIT_STATE;

    while(s.action != NULL_ACTION_ADDRESS) {
        (*s.action)(&s);
    }

    return 0;
}

void initial_action(struct state* ps) {
    ps->action = &handle_a;
}

void handle_a(struct state* ps) {
    ps->action = &handle_b;
}

void handle_b(struct state* ps) {
    ps->action = NULL_ACTION_ADDRESS;
}
票数 2
EN

Stack Overflow用户

发布于 2017-05-08 12:11:44

我想我明白了,我回顾了关于这个主题的所有不同的主题,我开始同意没有ansi C解决方案的地方,但我找到了一种方法来做这件事,满足我的需求。我在stackoverflow上看到的所有解决方案都是基于‘获取’标签的地址,然后将其填充到一个表中,然后索引这个表并转到,这既是使用了gcc/clang非ansi扩展,也是使用了asm扩展。

今天晚上我又试了一次,得到了这个。

在名为cgoto.h的包含文件中,我有以下内容

代码语言:javascript
复制
#ifndef CGOTO_dcl
#define CGOTO_dcl(N) int CGOTO_##N
#define CGOTO_LE(l) l,
#define CGOTO_LG(l) case l:goto l;
#define CGOTO_def(N)                                             \
  if(0){typedef enum {N(CGOTO_LE)} N; CGOTO_##N: switch(CGOTO_##N)\
  {N(CGOTO_LG) default:CGOTO_##N=0;goto CGOTO_##N;}}
#define CGOTO(N,i) CGOTO_##N=i; goto CGOTO_##N;
#endif

用法是这样的

代码语言:javascript
复制
#include <stdio.h>
#include "cgoto.h"
int f(int x)
{ //...
  CGOTO_dcl(gtb);
  //...
# define gtb(L) L(l0) L(l1) L(l2)
  CGOTO_def(gtb);
  //...

  CGOTO(gtb,x);
  l0: printf("error\n");
  return(0);

  //...

  l1:return(11);
  l2:return(22);
  l3:return(33);
}

int main()
{ printf("f(0)=%d f(1)=%d f(2)=%d,f(3)=%d\n",f(0),f(1),f(2),f(3));
}

在这个实现中,跳转的成本是2个跳转和一个顺序的switch(),然后是可优化的。因此,与函数调用相比,这是合理的性能,性能略低于&&label解决方案,但代价是可移植性。

有了这个实现,标签代码(语义动作)不会被限制在switch()中,所以我们可以实现具有共享语义动作的跳转表。

索引被分配给一个本地goto_table_index,使得函数使用这个可重入的(多线程),尽管优化器可以完全删除这种临时分配。

跳转表中的第一个标签是“特殊的”(在这个实现中),因为它捕获了超出界限的索引,第一个标签是“错误”标签。如果你的代码是防弹的,也就是说,你不可能得到一个越界的索引,那么第一个标签就没有特定的语义。

代码语言:javascript
复制
CGOTO_dcl(gtb);

声明跳转表'gtb‘自己的索引为一个自动整数,因此可重入。

代码语言:javascript
复制
  # define gtb(L) L(l0) L(l1) L(l2)
  CGOTO_def(gtb);

定义一个名为gtb的跳转表,标签可以用L(标签)输入/删除,所以它非常方便,这本质上是象征性的,即标签是有意义的名称。在#define作为switch()的情况下,标签添加/取消通常意味着#define重新编号是一个问题。

可以将#define与CGOTO_def()分开,但将它们放在一起更有意义。尽管CGOTO_def()必须放在函数局部声明之后,因为它包含一个switch(),这是代码。

uniq跳转表可以在函数中的多个位置使用。

代码语言:javascript
复制
CGOTO(gtb,x);
...
CGOTO(gtb,y);

一个标签可以在多个跳转表中输入

代码语言:javascript
复制
# define gtb1(L) L(l0) L(l1) L(l2)
  CGOTO_def(gtb1);
# define gtb2(L) L(l0) L(l4) L(l5)
  CGOTO_def(gtb2);

总而言之,这看起来可能很丑陋,然而,跳转表的定义通过两行#定义和CGOTO_def()是可管理的、实用的、半高性能的和可移植的。

我们回到FTN4 :)

干杯,菲

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43832336

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档