TC_P_程序设计_C语言状态机FSM_函数指针实现方式
TC_P_程序设计_状态机FSM_函数指针实现方式 2010年5月10日
1相关问题:
1.1自定义函数指针变量及其使用方法:
函数指针,顾名思义,它指向一个函数的入口地址,其定义及使用如下: ()
定义:returntype (*ptr) (typename variable,......)
返回类型 指针名称 指向函数的参数表。
代码
//
typedef void (*StateTranFun)(Fsm_Param_t * me,Signal_t sig);
//StateTranFun是一个自定义的,指向函数的指针变量,或者说,它定义了一个函数集合,定义了一组相同的函数操作,
//这个函数指针变量指向这样一类函数A: A的返回参数为void,A的函数参数为Fsm_Param_t * me,Signal_t sig
//我们可以定义有关于这类函数的具体实现:比如:
Fsm_Param_t fsm_paramA;
//StateTranFun是一个自定义的,指向函数的指针变量,或者说,它定义了一个函数集合,定义了一组相同的函数操作,
//这个函数指针变量指向这样一类函数A: A的返回参数为void,A的函数参数为Fsm_Param_t * me,Signal_t sig
//我们可以定义有关于这类函数的具体实现:比如:
Fsm_Param_t fsm_paramA;
Signal_t sigA;
StateTranFun funA;
*funA(fsm_paramA,sigA);
//
1.2 C语言运算符优先级:
见表格:(C语言运算符优先级 详细列表)可见得对于指针运算来说,->运算符的优先级是低于成员选择 .和[],() 要高于*,&这两个的.
举1个相关的例子:
假设我们自定义一个结构体:
Fsm_Param_t:如下
代码
//如下是一些查找代码段中,注释符号/**/ ,/,*出现次数的状态机的自定义变量和参数,
//其中,State_t是关于state的变量,共有CODE(包括普通字符),SLASH(/),STAR(*) COMMENT(/*)四种状态
//其中,Signal_t是关于event信号变量,包括输入Char信号,输入star信号,输入slash信号,另外,如果考虑entry和exit,还可自定义exit和entry两个枚举类型
typedef enum
{
CODE=0,
SLASH,
COMMENT,
STAR
}State_t;
typedef enum
{
CHAR_SIG,
STAR_SIG,
SLASH_SIG,
EXIT_SIG,
ENTRY_SIG
}Signal_t;
/*--------------------------------------------*/
//typedef struct Fsm Fsm_t;
typedef struct Fsm_Param Fsm_Param_t;
typedef void (*StateTranFun)(Fsm_Param_t * me,Signal_t sig);
//函数指针变量
typedef struct Fsm
{
StateTranFun statetranfun;
}Fsm_t;
typedef struct Fsm_Param
{
Fsm_t tranfun; //结构体变量Fsm_t
State_t currentstate; //状态变量State_t
long commentctr; //计数参数
}Fsm_Param_t,*P_Fsm_Param_t;
//其中,State_t是关于state的变量,共有CODE(包括普通字符),SLASH(/),STAR(*) COMMENT(/*)四种状态
//其中,Signal_t是关于event信号变量,包括输入Char信号,输入star信号,输入slash信号,另外,如果考虑entry和exit,还可自定义exit和entry两个枚举类型
typedef enum
{
CODE=0,
SLASH,
COMMENT,
STAR
}State_t;
typedef enum
{
CHAR_SIG,
STAR_SIG,
SLASH_SIG,
EXIT_SIG,
ENTRY_SIG
}Signal_t;
/*--------------------------------------------*/
//typedef struct Fsm Fsm_t;
typedef struct Fsm_Param Fsm_Param_t;
typedef void (*StateTranFun)(Fsm_Param_t * me,Signal_t sig);
//函数指针变量
typedef struct Fsm
{
StateTranFun statetranfun;
}Fsm_t;
typedef struct Fsm_Param
{
Fsm_t tranfun; //结构体变量Fsm_t
State_t currentstate; //状态变量State_t
long commentctr; //计数参数
}Fsm_Param_t,*P_Fsm_Param_t;
代码
Fsm_Param_t * me;
((*((me)->tranfun).statefun)((me),sig))
/*
step 1 (me)// ()意义:在宏定义中,如果输入的me是一个复合结构的话,用()保证这个复合结构完整,避免出现没有预知到的,错误,比如如果me在宏运用中,代表&test,那么没有加上(),就可能使得(me)->tranfun整个意义变了
(&test)->tranfun 和&test->tranfun是有区别的
step2 (me)->tranfun
step3 ((me)->tranfun)
step4 (((me)->tranfun).statefun)
step5 *(((me)->tranfun).statefun)
step6 (*(((me)->tranfun).statefun))
step7 (*(((me)->tranfun).statefun))((me),sig)
step8 ((*(((me)->tranfun).statefun))((me),sig))
可见,宏是一个必须非常小心的东西,稍微偏差,都可能出错的
*/
((*((me)->tranfun).statefun)((me),sig))
/*
step 1 (me)// ()意义:在宏定义中,如果输入的me是一个复合结构的话,用()保证这个复合结构完整,避免出现没有预知到的,错误,比如如果me在宏运用中,代表&test,那么没有加上(),就可能使得(me)->tranfun整个意义变了
(&test)->tranfun 和&test->tranfun是有区别的
step2 (me)->tranfun
step3 ((me)->tranfun)
step4 (((me)->tranfun).statefun)
step5 *(((me)->tranfun).statefun)
step6 (*(((me)->tranfun).statefun))
step7 (*(((me)->tranfun).statefun))((me),sig)
step8 ((*(((me)->tranfun).statefun))((me),sig))
可见,宏是一个必须非常小心的东西,稍微偏差,都可能出错的
*/
(((me)->tranfun).statetranfun=(StateTranFun)(target))
//这个=操作就是让target这个参数先强制转换为(StateTranFun)类型的变量,
再将其赋值于((me)->tranfun).statetranfun这个变量
再将其赋值于((me)->tranfun).statetranfun这个变量
代码
/*
step1 (me)
step2 (me)->tranfun
step3 ((me)->tranfun).statetranfun
step4 ((me)->tranfun).statetranfun=(StateTranFun)(target)
step5 (((me)->tranfun).statetranfun=(StateTranFun)(target))
*/
step1 (me)
step2 (me)->tranfun
step3 ((me)->tranfun).statetranfun
step4 ((me)->tranfun).statetranfun=(StateTranFun)(target)
step5 (((me)->tranfun).statetranfun=(StateTranFun)(target))
*/
1.3 关于所谓的表驱动:
表驱动有一个非常好用的地方.那就是取代一部分基于switch和if语句架构的代码段,随着switch case语句的增加,整个switch代码框架的可读性和维护性在下降
而,表驱动能够很好解决这个问题
表驱动一个简单的实例:
代码
static void CParser4commentOnCHAR(CParser1_t *me)
{
printf("currentstate:COMMENT\n");
++me->commentctr; /* count the comment character */
}
static void CParser4commentOnSTAR(CParser1_t *me)
{
printf("currentstate:COMMENT ");
TRAN(me,CParser4star); /* transition to "star" */
}
static void CParser4commentOnSLASH(CParser1_t *me)
{
printf("currentstate:COMMENT\n");
++me->commentctr; /* count the comment character */
}
void CParser4comment(CParser1_t *me,Signal_t sig)
{
static const void(*lookup[])(CParser1_t *)=
{
CParser4commentOnCHAR,
CParser4commentOnSTAR,
CParser4commentOnSLASH
};
me->currentstate=COMMENT;
printf("currentstate:COMMENT ");
(*lookup[sig])(me);
}
//在函数CParser4comment中,我们在静态变量区间上,定义了一个cosnt类型的数组,一个比较特别的数组,它存储着,不是一般的普通变量,而是一群类型相同的函//数,或者说是定义了一个函数指针数组,这个数值的索引是Signal_t sig这么一个变量,在这里也要注意到枚举类型变量Signal_t的成员的先后顺序和这个数组存储的变量的前后关系
{
printf("currentstate:COMMENT\n");
++me->commentctr; /* count the comment character */
}
static void CParser4commentOnSTAR(CParser1_t *me)
{
printf("currentstate:COMMENT ");
TRAN(me,CParser4star); /* transition to "star" */
}
static void CParser4commentOnSLASH(CParser1_t *me)
{
printf("currentstate:COMMENT\n");
++me->commentctr; /* count the comment character */
}
void CParser4comment(CParser1_t *me,Signal_t sig)
{
static const void(*lookup[])(CParser1_t *)=
{
CParser4commentOnCHAR,
CParser4commentOnSTAR,
CParser4commentOnSLASH
};
me->currentstate=COMMENT;
printf("currentstate:COMMENT ");
(*lookup[sig])(me);
}
//在函数CParser4comment中,我们在静态变量区间上,定义了一个cosnt类型的数组,一个比较特别的数组,它存储着,不是一般的普通变量,而是一群类型相同的函//数,或者说是定义了一个函数指针数组,这个数值的索引是Signal_t sig这么一个变量,在这里也要注意到枚举类型变量Signal_t的成员的先后顺序和这个数组存储的变量的前后关系
使得lookup[CHAR_SIG]对应CParser4commentOnCHAR,等等
1.4关于一个小小的问题scanf函数:
char name[30];
scanf("%s",name)
scanf函数有一个特点:在输入结束,会自动补上'\0'这个东西,字符串数组结束标志
这样的结果,有利也有弊,接下来的代码,我们就会看到它的好处,同时也是它的坏处.
源代码: 在用状态机原理进行软件设计.pdf 如下代码有待修改整理,可能存在错误:
h文件:
代码
#ifndef _STATE_MECHINE_H_
#define _STATE_MECHINE_H_
typedef enum
{
CODE=0,
SLASH,
COMMENT,
STAR
}State_t;
typedef enum
{
CHAR_SIG,
STAR_SIG,
SLASH_SIG,
EXIT_SIG,
ENTRY_SIG
}Signal_t;
typedef struct CParser1 CParser1_t;
typedef struct Fsm Fsm_t;
#if 0
typedef void (*StateTranFun)(void * me,Signal_t sig);
#endif
#if 1
typedef void (*StateTranFun)(CParser1_t * me,Signal_t sig);//记住,StateTranFun是一个函数指针变量,
#endif
struct Fsm
{
StateTranFun statetranfun;
};
typedef struct CParser1
{
Fsm_t tranfun;
State_t currentstate;
long commentctr;
}CParser1_t;
#define FsmDispatch(me,sig) (*((me)->tranfun).statetranfun)((me),sig)
#define FsmInit(me) (*((me)->tranfun).statetranfun)((me),0)
#define TRAN(me,target) (((me)->tranfun).statetranfun=(StateTranFun)(target)
#define TRAN_EE(target) do{\
*((Fsm_t *)me)->state)(me,EXIT_SIG); \
((Fsm_t *)me)->state=(State_t)(target);\
*((Fsm_t *)me)->state)(me,ENTRY_SIG); \
}while(0)
extern void CParser4code (CParser1_t *me,Signal_t sig);
extern void CParser4slash(CParser1_t *me,Signal_t sig);
extern void CParser4comment(CParser1_t *me,Signal_t sig);
extern void CParser4star (CParser1_t *me,Signal_t sig);
extern CParser1_t *CParser4Ctor(CParser1_t *me);
extern Fsm_t * FsmCtor(Fsm_t *me,StateTranFun initial);
#endif
#define _STATE_MECHINE_H_
typedef enum
{
CODE=0,
SLASH,
COMMENT,
STAR
}State_t;
typedef enum
{
CHAR_SIG,
STAR_SIG,
SLASH_SIG,
EXIT_SIG,
ENTRY_SIG
}Signal_t;
typedef struct CParser1 CParser1_t;
typedef struct Fsm Fsm_t;
#if 0
typedef void (*StateTranFun)(void * me,Signal_t sig);
#endif
#if 1
typedef void (*StateTranFun)(CParser1_t * me,Signal_t sig);//记住,StateTranFun是一个函数指针变量,
#endif
struct Fsm
{
StateTranFun statetranfun;
};
typedef struct CParser1
{
Fsm_t tranfun;
State_t currentstate;
long commentctr;
}CParser1_t;
#define FsmDispatch(me,sig) (*((me)->tranfun).statetranfun)((me),sig)
#define FsmInit(me) (*((me)->tranfun).statetranfun)((me),0)
#define TRAN(me,target) (((me)->tranfun).statetranfun=(StateTranFun)(target)
#define TRAN_EE(target) do{\
*((Fsm_t *)me)->state)(me,EXIT_SIG); \
((Fsm_t *)me)->state=(State_t)(target);\
*((Fsm_t *)me)->state)(me,ENTRY_SIG); \
}while(0)
extern void CParser4code (CParser1_t *me,Signal_t sig);
extern void CParser4slash(CParser1_t *me,Signal_t sig);
extern void CParser4comment(CParser1_t *me,Signal_t sig);
extern void CParser4star (CParser1_t *me,Signal_t sig);
extern CParser1_t *CParser4Ctor(CParser1_t *me);
extern Fsm_t * FsmCtor(Fsm_t *me,StateTranFun initial);
#endif
c 文件:
代码
#include"state_mechine.h"
#include"stdio.h"
void CParser4code (CParser1_t *me,Signal_t sig);
void CParser4slash(CParser1_t *me,Signal_t sig);
void CParser4comment(CParser1_t *me,Signal_t sig);
void CParser4star (CParser1_t *me,Signal_t sig);
/*------------------------------------------------*/
static void CParser4commentOnCHAR(CParser1_t *me)
{
printf("currentstate:COMMENT\n");
++me->commentctr; /* count the comment character */
}
static void CParser4commentOnSTAR(CParser1_t *me)
{
printf("currentstate:COMMENT ");
TRAN(me,CParser4star); /* transition to "star" */
}
static void CParser4commentOnSLASH(CParser1_t *me)
{
printf("currentstate:COMMENT\n");
++me->commentctr; /* count the comment character */
}
void CParser4Initial(CParser1_t *me,Signal_t sig)
{
me->commentctr=0;
me->currentstate=CODE;
TRAN(me,CParser4code);
}
Fsm_t * FsmCtor(Fsm_t *me,StateTranFun initial)
{
me->statetranfun=initial;
return me;
}
CParser1_t *CParser4Ctor(CParser1_t *me)
{
FsmCtor(&(me->tranfun),((StateTranFun)CParser4Initial));
return me;
}
/*------------------------------------------------*/
void CParser4code (CParser1_t *me,Signal_t sig)
{
me->currentstate=CODE;
printf("currentstate:CODE ");
switch(sig)
{
case SLASH_SIG:
printf("nextstate:SlASH");
TRAN(me,CParser4slash);
break;
}
printf("\n");
}
void CParser4slash(CParser1_t *me,Signal_t sig)
{
me->currentstate=SLASH;
printf("currentstate:SLASH ");
switch(sig)
{
case STAR_SIG:
me->commentctr+=2;
printf("nextstate:COMMENTn");
TRAN(me,CParser4comment);
break;
case CHAR_SIG:
printf("nextstate:CODE");
TRAN(me,CParser4code);
break;
}
printf("\n");
}
void CParser4comment(CParser1_t *me,Signal_t sig)
{
static const void(*lookup[])(CParser1_t *)={
CParser4commentOnCHAR,
CParser4commentOnSTAR,
CParser4commentOnSLASH
};
me->currentstate=COMMENT;
printf("currentstate:COMMENT ");
(*lookup[sig])(me);
}
void CParser4star (CParser1_t *me,Signal_t sig)
{
me->currentstate=STAR;
printf("currentstate:STAR ");
switch(sig)
{
case STAR_SIG:
++me->commentctr;
break;
case CHAR_SIG:
me->commentctr+=2;
TRAN(me,CParser4comment);
printf("nextstate:COMMENT");
break;
case SLASH_SIG:
me->commentctr+=2;
TRAN(me,CParser4code);
printf("nextstate:CODE");
break;
}
printf("\n");
}
/*------------------------------------------------*/
#include"stdio.h"
void CParser4code (CParser1_t *me,Signal_t sig);
void CParser4slash(CParser1_t *me,Signal_t sig);
void CParser4comment(CParser1_t *me,Signal_t sig);
void CParser4star (CParser1_t *me,Signal_t sig);
/*------------------------------------------------*/
static void CParser4commentOnCHAR(CParser1_t *me)
{
printf("currentstate:COMMENT\n");
++me->commentctr; /* count the comment character */
}
static void CParser4commentOnSTAR(CParser1_t *me)
{
printf("currentstate:COMMENT ");
TRAN(me,CParser4star); /* transition to "star" */
}
static void CParser4commentOnSLASH(CParser1_t *me)
{
printf("currentstate:COMMENT\n");
++me->commentctr; /* count the comment character */
}
void CParser4Initial(CParser1_t *me,Signal_t sig)
{
me->commentctr=0;
me->currentstate=CODE;
TRAN(me,CParser4code);
}
Fsm_t * FsmCtor(Fsm_t *me,StateTranFun initial)
{
me->statetranfun=initial;
return me;
}
CParser1_t *CParser4Ctor(CParser1_t *me)
{
FsmCtor(&(me->tranfun),((StateTranFun)CParser4Initial));
return me;
}
/*------------------------------------------------*/
void CParser4code (CParser1_t *me,Signal_t sig)
{
me->currentstate=CODE;
printf("currentstate:CODE ");
switch(sig)
{
case SLASH_SIG:
printf("nextstate:SlASH");
TRAN(me,CParser4slash);
break;
}
printf("\n");
}
void CParser4slash(CParser1_t *me,Signal_t sig)
{
me->currentstate=SLASH;
printf("currentstate:SLASH ");
switch(sig)
{
case STAR_SIG:
me->commentctr+=2;
printf("nextstate:COMMENTn");
TRAN(me,CParser4comment);
break;
case CHAR_SIG:
printf("nextstate:CODE");
TRAN(me,CParser4code);
break;
}
printf("\n");
}
void CParser4comment(CParser1_t *me,Signal_t sig)
{
static const void(*lookup[])(CParser1_t *)={
CParser4commentOnCHAR,
CParser4commentOnSTAR,
CParser4commentOnSLASH
};
me->currentstate=COMMENT;
printf("currentstate:COMMENT ");
(*lookup[sig])(me);
}
void CParser4star (CParser1_t *me,Signal_t sig)
{
me->currentstate=STAR;
printf("currentstate:STAR ");
switch(sig)
{
case STAR_SIG:
++me->commentctr;
break;
case CHAR_SIG:
me->commentctr+=2;
TRAN(me,CParser4comment);
printf("nextstate:COMMENT");
break;
case SLASH_SIG:
me->commentctr+=2;
TRAN(me,CParser4code);
printf("nextstate:CODE");
break;
}
printf("\n");
}
/*------------------------------------------------*/
main文件:
代码
#include <stdlib.h>
#include <stdio.h>
#include"state_mechine.h"
static CParser1_t cparser;
void main(void)
{
char name[60];
char *p;
p=name;
scanf("%s",name);
CParser4Ctor(&cparser);
FsmInit(&cparser);
while (*p!='\0')
{
int sig;
switch (*p)
{
case '/': sig = SLASH_SIG; break;
case '*': sig = STAR_SIG; break;
default: sig = CHAR_SIG; break;
}
FsmDispatch(&cparser,sig);
++p;
}
}
#include <stdio.h>
#include"state_mechine.h"
static CParser1_t cparser;
void main(void)
{
char name[60];
char *p;
p=name;
scanf("%s",name);
CParser4Ctor(&cparser);
FsmInit(&cparser);
while (*p!='\0')
{
int sig;
switch (*p)
{
case '/': sig = SLASH_SIG; break;
case '*': sig = STAR_SIG; break;
default: sig = CHAR_SIG; break;
}
FsmDispatch(&cparser,sig);
++p;
}
}
附:UML图原理:
附:运行效果图