TC_P_程序设计_C语言状态机FSM_函数指针实现方式

TC_P_程序设计_状态机FSM_函数指针实现方式 2010年5月10日

 1相关问题:

1.1自定义函数指针变量及其使用方法:

函数指针,顾名思义,它指向一个函数的入口地址,其定义及使用如下:  ()
  定义:returntype     (*ptr)               (typename   variable,......)   
            返回类型           指针名称         指向函数的参数表。  

 

ExpandedBlockStart.gif 代码
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;
Signal_t sigA;
StateTranFun  funA;
 
*funA(fsm_paramA,sigA);
 

//

 

 

1.2 C语言运算符优先级:

见表格:(C语言运算符优先级 详细列表)可见得对于指针运算来说,->运算符的优先级是低于成员选择 .[],() 高于*,&这两个的.

举1个相关的例子:

假设我们自定义一个结构体:

Fsm_Param_t:如下

ExpandedBlockStart.gif 代码
// 如下是一些查找代码段中,注释符号/**/ ,/,*出现次数的状态机的自定义变量和参数,
// 其中,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;

 

 

ExpandedBlockStart.gif 代码
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).statetranfun=(StateTranFun)(target))
// 这个=操作就是让target这个参数先强制转换为(StateTranFun)类型的变量,
再将其赋值于((me) -> tranfun).statetranfun这个变量

 

ExpandedBlockStart.gif 代码
/*
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代码框架的可读性和维护性在下降

而,表驱动能够很好解决这个问题

表驱动一个简单的实例:

 

ExpandedBlockStart.gif 代码
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的成员的先后顺序和这个数组存储的变量的前后关系
使得lookup[CHAR_SIG]对应CParser4commentOnCHAR,等等

 

 1.4关于一个小小的问题scanf函数:

char name[30];

scanf("%s",name)

scanf函数有一个特点:在输入结束,会自动补上'\0'这个东西,字符串数组结束标志

这样的结果,有利也有弊,接下来的代码,我们就会看到它的好处,同时也是它的坏处.

 源代码:  在用状态机原理进行软件设计.pdf  如下代码有待修改整理,可能存在错误:

h文件:

 

ExpandedBlockStart.gif 代码
#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

 

 

 c 文件:

 

 

ExpandedBlockStart.gif 代码
#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 " );
}
/* ------------------------------------------------ */

 

main文件:

 

ExpandedBlockStart.gif 代码
#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; 
  }
}

 

附:UML图原理:

附:运行效果图

 

 

 

 

转载于:https://www.cnblogs.com/fleetwgx/articles/1731890.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值