TC_P_程序设计_状态机FSM_函数指针实现方式 2010年5月10日
1相关问题:
1.1自定义函数指针变量及其使用方法:
函数指针,顾名思义,它指向一个函数的入口地址,其定义及使用如下: ()
定义:returntype (*ptr) (typename variable,......)
返回类型 指针名称 指向函数的参数表。
// StateTranFun是一个自定义的,指向函数的指针变量,或者说,它定义了一个函数集合,定义了一组相同的函数操作,
// 这个函数指针变量指向这样一类函数A: A的返回参数为void,A的函数参数为Fsm_Param_t * me,Signal_t sig
// 我们可以定义有关于这类函数的具体实现:比如:
Fsm_Param_t fsm_paramA;
//
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;
(( * ((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这个变量
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代码框架的可读性和维护性在下降
而,表驱动能够很好解决这个问题
表驱动一个简单的实例:
{
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的成员的先后顺序和这个数组存储的变量的前后关系
1.4关于一个小小的问题scanf函数:
char name[30];
scanf("%s",name)
scanf函数有一个特点:在输入结束,会自动补上'\0'这个东西,字符串数组结束标志
这样的结果,有利也有弊,接下来的代码,我们就会看到它的好处,同时也是它的坏处.
源代码: 在用状态机原理进行软件设计.pdf 如下代码有待修改整理,可能存在错误:
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
c 文件:
#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 < 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图原理:
附:运行效果图