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