C89计算goto(再次)如何 [英] C89 computed goto (again) how to

查看:121
本文介绍了C89计算goto(再次)如何的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我需要在可移植的ansi-C中对此进行编码.

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

有人知道该怎么做吗?

解决方案

我想我明白了,我复习了有关该主题的所有主题,并且我开始同意那里没有ansi C解决方案,但我发现了满足我需求的方式.我在stackoverflow上看到的所有解决方案都是基于获取"标签的addr,然后将其填充到表中,然后对该表进行索引,然后转到goto的,这都是gcc/clang non ansi扩展或asm扩展.

我又给它加了一次托尼特,并得到了它.

在一个名为cgoto.h的包含文件中,我有这个

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

在此实现中,跳转的成本为2次跳转,并且switch()是顺序的,然后是可优化的.因此,与函数调用相比,此方法的性能合理,但以可移植性为代价,其性能比&&& amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp;}统一元发布计划

通过此实现,标签代码(语义动作)不限于switch(),因此我们可以使用共享的语义动作来实现跳转表.

将索引分配给本地goto_table_index,尽管优化程序可以完全删除此临时分配,但该函数使用此重入(多线程)功能.

在跳转表中的第一个标签是特殊"标签(在此实现中),因为它捕获超出范围的索引,第一个标签是错误"标签.如果您的代码是防弹的,即无法获得超出范围的索引,那么第一个标签就没有特定的语义.

CGOTO_dcl(gtb);

将跳转表'gtb'自己的索引声明为自动整数,因此可重入.

  # define gtb(L) L(l0) L(l1) L(l2)
  CGOTO_def(gtb);

定义一个名为gtb的跳转表,可以使用L(label)输入/删除标签,因此非常方便,这本质上是象征性的,即标签是具有含义的名称.在#define作为switch()的情况下,标签的添加/抑制通常意味着#define重编号是一个问题.

可以将#define与CGOTO_def()分开,但将它们保持在一起更为有意义.尽管CGOTO_def()必须包含在代码中,但它必须放置在函数本地声明之后,因为它包含一个switch().

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了:)

干杯, 皮

I need to code an automata, and I bumped into this old need of a computed goto (ala fortran4 :) )

I need to code this in a portable ansi-C.

I want to stay away from the "don't do that", away from longjmp/setjmp, away from embedded ASM(), away from non ansi-C extensions.

Does anyone know how to do this?

解决方案

I think I got it, I reviewed all the various threads on this topics and I started to agree that that there where no ansi C solutions, yet I found an way to do this that fit my needs. All solution I saw on stackoverflow where based on the idea to 'get' the addr of a label, then stuff it into a table, then index this table and goto, this is both with gcc/clang non ansi extension or the asm extension.

I gave it another try tonite and got this.

In an include file named cgoto.h I have this

#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

The usage is like this

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

In this implementation, the cost of jumping is 2 jumps and a switch() that is sequential, then optimisable. So this is reasonably performing compared to function call, a little less performing than &&label solution at the cost of portability.

With this implementation, labels code (semantic actions) are not confined into a switch() so we can implement jump table with shared semantic actions.

The index is assigned to a local goto_table_index, making the function using this re-entrant (multi threadable), though the optimiser can remove altogether this temp assignment.

The 1st Label in a jump table is 'special' (on this implementation) in the sense that it catch index out of bound, the first label is the 'error' label. If your code is bullet proof, i.e there is no way you can get an out of bound index, then the 1st label has not particular semantic.

CGOTO_dcl(gtb);

Declare the jump table 'gtb' own index as an auto integer so reentrant.

  # define gtb(L) L(l0) L(l1) L(l2)
  CGOTO_def(gtb);

Define a jump table named gtb, labels can be entered/removed with L(label) so it is pretty convenient, and this is symbolic by nature, i.e the labels are name with a meaning. With #define as a switch() case, labels addition/suppression often mean #define renumbering that is a problem.

The #define can be separated from the CGOTO_def() but it make more sense to keep them together. The CGOTO_def() though got to be placed after the function local declaration as it contain a switch() that is code.

A uniq jump table can be used in multiple place in the function.

CGOTO(gtb,x);
...
CGOTO(gtb,y);

A label may be entered in multiple jump table

# define gtb1(L) L(l0) L(l1) L(l2)
  CGOTO_def(gtb1);
# define gtb2(L) L(l0) L(l4) L(l5)
  CGOTO_def(gtb2);

So all in all, this may looks ugly, yet, the jump table definition though 2 line the #define and the CGOTO_def() is manageable and practical, semi performant, and portable.

We are back to FTN4 :)

Cheers, Phi

这篇关于C89计算goto(再次)如何的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆