C89计算转到(再次)如何

C89计算转到(再次)如何,c,goto,C,Goto,我需要编写一个自动机的代码,我偶然遇到了一个旧的需要计算goto(ala fortran4:) 我需要在一个可移植的ansi-C中进行编码 我想远离“不要那样做”,远离longjmp/setjmp,远离嵌入式ASM(),远离非ansi-C扩展 有人知道怎么做吗?就像我在评论中说的那样,尽管你呼吁不要使用goto以外的任何东西,但标准C没有什么可以提供的 适当地设计您的状态,并将指向该状态的指针传递给处理程序函数以供修改。这样处理程序就可以设置下一个要调用的函数。大概是这样的: struct st

我需要编写一个自动机的代码,我偶然遇到了一个旧的需要计算goto(ala fortran4:)

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

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


有人知道怎么做吗?

就像我在评论中说的那样,尽管你呼吁不要使用goto以外的任何东西,但标准C没有什么可以提供的

适当地设计您的状态,并将指向该状态的指针传递给处理程序函数以供修改。这样处理程序就可以设置下一个要调用的函数。大概是这样的:

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;
}

我想我明白了,我回顾了关于这个主题的所有线程,我开始同意没有ansi C解决方案,但我找到了一种适合我需要的方法。我在stackoverflow上看到的所有解决方案都是基于“获取”标签的addr,然后将其填充到一个表中,然后索引这个表和goto,这两种扩展都是gcc/clang非ansi扩展或asm扩展

我又试了一次tonite,得到了这个

在一个名为cgoto.h的include文件中,我有一个

#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
用法是这样的

#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));
}
将跳转表“gtb”自身索引声明为自动整数,以便可重入

  # define gtb(L) L(l0) L(l1) L(l2)
  CGOTO_def(gtb);
定义一个名为gtb的跳转表,标签可以用L(标签)输入/删除,因此非常方便,这本质上是符号化的,即标签是有意义的名称。对于#define as a switch()情况,标签添加/抑制通常意味着#define重新编号,这是一个问题

可以将#define与CGOTO_def()分开,但将它们放在一起更有意义。不过,CGOTO_def()必须放在函数本地声明之后,因为它包含一个开关(),该开关是代码

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

CGOTO(gtb,x);
...
CGOTO(gtb,y);
可以在多跳表中输入标签

# define gtb1(L) L(l0) L(l1) L(l2)
  CGOTO_def(gtb1);
# define gtb2(L) L(l0) L(l4) L(l5)
  CGOTO_def(gtb2);
总而言之,这可能看起来很难看,但是,跳转表定义(尽管有两行#define和CGOTO_def())是可管理的、实用的、半性能的和可移植的

我们回到FTN4:)

干杯,
Phi

好吧,所谓的“计算转到”在C中只作为不可移植的扩展存在。也许有一种更简洁的方法来解决您的问题。问题是什么?ansi C中没有这样的机制。正确设计您的状态表示,并使用接受其地址的函数指针。顺便说一句,如果您想要符合ansi标准(即C89),您的标题是误导性的。
开关
是计算转到。我不知道“计算转到”是什么。我听起来有点恶心,我猜我不需要知道这件事?这是一些非常可怕的意大利面代码。一开始就需要一个“计算转到”,这很可能源于程序设计的混乱,而所有这些疯狂的宏元编程都不能很好地解决任何现有问题。你的原始问题的实际解决方案几乎肯定是修复原始的程序设计。。。因为我们刚刚把所有好的编程实践都抛到了窗外。。。我无法理解setjmp/longjmp函数会如何变得更糟。老实说,这是一个非常有趣的解决方案
case l:goto l
为编译器提供了足够的信息,它甚至可以优化到单个跳转。对所有的C“精英主义者”感到抱歉;他们无法理解为什么有人问这样的问题。我甚至让其中一个有100000多名代表的人告诉我“你不能在标题中定义函数”。
# define gtb1(L) L(l0) L(l1) L(l2)
  CGOTO_def(gtb1);
# define gtb2(L) L(l0) L(l4) L(l5)
  CGOTO_def(gtb2);