
之前写过一篇状态机的实用文章,很多朋友说有几个地方有点难度不易理解,今天给大家换种简单写法,使用函数指针的方法实现状态机。 状态机简介有限状态机FSM是有限个状态及在这些状态之间的转移和动作等行为的数学模型,是一种逻辑单元内部的高效编程方法,可以根据不同状态或者消息类型进行相应的处理逻辑,使得程序逻辑清晰易懂。 函数指针实现FSM使用函数指针实现FSM可以分为3个步骤
state_1=1, B3 H% {+ a `8 t3 q, T state_2,- h9 r0 j* W* _, q5 b state_3, state_4 }State;$ B, ]0 p1 o* E- t9 f6 X
event_1=1, event_2,/ B3 F. {: u% T0 n m* a event_3,, T, V c; z/ o' h9 n+ z! T, o! D event_4, event_5+ v4 U8 D* f& m+ P8 x: b# | Y6 o }EventID;" k7 u& o O% a S
{4 o8 I1 n7 E( u, @/ G int event; //事件 int CurState; //当前状态! w& o9 M8 @) m F& A void (*eventActFun)(); //函数指针 int NextState; //下一个状态; `$ S, _- r M9 F }StateTable;0 i2 A! U/ {1 ~' L) _* ^
{0 t; R9 Z0 k# U* L Y+ A printf("this is f121\n"); }5 Q% G0 s R$ @& ^8 Q. v V void f221()7 ?% i. h6 E. N2 l* G3 D {5 g2 f* f9 v: e F# L printf("this is f221\n");0 \) C6 }2 ^) _6 d+ z } void f321() { printf("this is f321\n"); }6 h4 I) ~! ]/ i7 E8 W1 c void f122() { printf("this is f122\n"); }. @2 j7 d0 t8 P9 e* f StateTable fTable[] = { //{到来的事件,当前的状态,将要要执行的函数,下一个状态} { event_1, state_1, f121, event_2 },$ c& H, ~& i) I. c0 a+ { { event_2, state_2, f221, event_3 }, { event_3, state_3, f321, event_4 }, { event_4, state_4, f122, event_1 },7 r. }; U" K* Z0 S4 r( O //add your code here };8 Y9 O8 Z/ p5 e0 R: n
typedef struct { int curState;//当前状态. t$ D/ x7 t$ Z1 x StateTable * stateTable;//状态表* K7 N, J5 B& e. ^! a int size;//表的项数 }fsmType; y' h2 {, x- R /*状态机注册,给它一个状态表*/ void fsmRegist(fsmType* pFsm, StateTable* pTable) { pFsm->stateTable = pTable;7 ]4 Z) e& r, T }5 I# N6 I- J2 Q7 I /*状态迁移*/ void fsmStateTransfer(fsmType* pFsm, int state) {0 P% a2 V: \ a+ b0 z2 ` pFsm->curState = state;. a, ^3 u0 P1 P2 @+ _3 d% X }" [7 r! b, I) y/ t s2 w0 |: r 3 X8 c8 N$ S6 W" j4 O5 }; G8 Y /*事件处理*/' `0 F; x: l. z+ T5 j- _ void fsmEventHandle(fsmType* pFsm, int event) {4 @. y. s G' {; G( {6 k7 A StateTable* pActTable = pFsm->stateTable; void (*eventActFun)() = NULL; //函数指针初始化为空 int NextState;; N3 l" g. f/ }% p/ b, N$ H9 n int CurState = pFsm->curState;& W( |$ f3 w4 Y# j" E0 t6 u9 h7 T8 y) ] int maxNum = pFsm->size; int flag = 0; //标识是否满足条件+ x$ i4 k% n5 d - a3 p" t( H4 K! W /*获取当前动作函数*/ for (int i = 0; i<maxNum; i++) {% v- f3 N# U% a. z5 x) _( v; x //当且仅当当前状态下来个指定的事件,我才执行它: i W) q3 Y" q; w if (event == pActTable.event && CurState == pActTable.CurState) { flag = 1; eventActFun = pActTable.eventActFun;+ a( S2 j& Q2 l' g: Z$ \ NextState = pActTable.NextState; break; } } if (flag) //如果满足条件了 { /*动作执行*/ if (eventActFun)6 Z; q: c- X, j, H7 f {- E2 h$ }* R7 f, m eventActFun();! X. _/ U) i4 Q, W3 Z }% J' @. S( M9 F 1 O' [1 z! A4 {" q' U6 p" b3 z4 c //跳转到下一个状态. O: f e. F8 b. x6 Y% r. y5 p- J fsmStateTransfer(pFsm, NextState); } else { printf("there is no match\n");/ s5 {4 O4 i7 i. ?' b# o }. [9 r% \1 I- D M$ h! b8 [5 r }+ T& p3 _. U* X! ]3 e) V 附代码 代码直接复制过去就行啦,本想打包的,太麻烦了。 测试程序//编译器:http://www.dooccn.com/cpp///来源:技术让梦想更伟大 //作者:李肖遥# _3 X/ I. k. w1 ?& Z #include <stdio.h> typedef enum {% C% i' O" V0 R# n' M9 K state_1=1, state_2,+ t/ [3 O7 H n) d state_3, state_4- L* V) e; Q/ K$ u }State;* o! ]* H( @, i; ~* I5 B; s3 K typedef enum{ event_1=1,, U9 q+ ~8 c+ r) n event_2,' \3 ?8 _8 \+ i* P. M event_3, Z7 O8 I# Z+ ~! z event_4, event_5 }EventID;( p5 R4 ~) l2 w1 t2 t$ [ ' {$ H. o% h3 ~' s0 k4 |5 m# s9 r typedef struct { int event; //事件2 Q; O7 H' V" q# K# B G/ _' ] int CurState; //当前状态& w1 C+ H- p+ o3 g void (*eventActFun)(); //函数指针 int NextState; //下一个状态 }StateTable; void f121() {6 k9 I7 f+ h0 Q printf("this is f121\n");7 Z. ]6 u1 G7 c }7 N; W3 K( J3 ?8 \' V3 _7 R void f221() { printf("this is f221\n");2 o3 C$ E3 v# q+ }! o; S% W* ~4 t } void f321() { printf("this is f321\n"); C4 d( D, F& C } void f122()% b- A# ]) t$ d; I { printf("this is f122\n");, \& y( Q% e% X }( O" D! E1 H, c StateTable fTable[] = {! s" D9 m: h. k. a //{到来的事件,当前的状态,将要要执行的函数,下一个状态}8 F8 ?5 ]" T9 i3 j6 o# r& e { event_1, state_1, f121, event_2 },/ ~4 A0 b0 b$ b( I4 I0 b" a { event_2, state_2, f221, event_3 },. z6 I$ ^# m% H/ c" X { event_3, state_3, f321, event_4 },. u' W; |# [2 J& _4 s { event_4, state_4, f122, event_1 }, //add your code here) T0 ^, |& p7 }; h& H9 z9 h) z- N }; /*状态机类型*/ typedef struct {! y5 W! r; j: D* l* w& j% Q V; c int curState;//当前状态: e V c+ u" z s! R: z/ B StateTable * stateTable;//状态表 int size;//表的项数% s% \3 N: @0 R) h& I }fsmType;) E3 ~2 O* }. H. z & @+ Y1 I- Y) j* `4 R7 [/ r /*状态机注册,给它一个状态表*/$ h. B2 T: M# i7 t; x1 e# L void fsmRegist(fsmType* pFsm, StateTable* pTable)0 A0 y( k6 j# X( t( l {6 W1 ?) w/ T8 n) ]' A pFsm->stateTable = pTable;6 X8 ]# R: n9 D- W! L5 s+ r } 7 M& w' B; z$ D, l /*状态迁移*/9 ?$ q2 T! f' G3 M8 p3 [7 W void fsmStateTransfer(fsmType* pFsm, int state) { pFsm->curState = state;: T- j7 `% D% @ }: H" e1 m6 B2 l" _% F7 Q0 a( { 6 V* k7 [+ E$ E) D. }+ m7 ^; x /*事件处理*/& H) p1 m. D, ^: I6 M D void fsmEventHandle(fsmType* pFsm, int event)8 R# f8 o! A. \, J. K { StateTable* pActTable = pFsm->stateTable; `2 T# K2 i M" R6 j: B3 G void (*eventActFun)() = NULL; //函数指针初始化为空 int NextState;' y5 D- e: ?7 y0 D1 u# @ int CurState = pFsm->curState; int maxNum = pFsm->size; int flag = 0; //标识是否满足条件" @+ E# l, v& W; B/ Y" A 1 u' r/ ^. \5 ?1 R8 v /*获取当前动作函数*/, N( |3 A/ v6 q* Z for (int i = 0; i<maxNum; i++) {: f) W! V% k8 A# [# e //当且仅当当前状态下来个指定的事件,我才执行它 if (event == pActTable.event && CurState == pActTable.CurState) {8 u1 T; e' W5 s3 N flag = 1;: S5 z3 _/ f0 ^: ~; E* f; U eventActFun = pActTable.eventActFun; NextState = pActTable.NextState; break; }; g( K3 M" A( ^8 q } $ [) Q& T$ }/ y7 ^& A, A5 O if (flag) //如果满足条件了 { /*动作执行*/ if (eventActFun)5 z, L4 F. o) P7 P& F( ] { eventActFun();1 b: f. z/ s/ y/ Y7 [! z+ F- V! Q } //跳转到下一个状态( H+ A! E. R. o/ F+ { fsmStateTransfer(pFsm, NextState); }0 W1 U# T5 e& N# s else {1 k: C: x: h* b. i printf("there is no match\n");5 u' {% p. D, d/ @ w0 H7 W8 d+ t } } ) L G0 h, H, }# @6 x int main() { fsmType pType; fsmRegist(&pType,fTable); pType.curState = state_1;* R$ O3 y$ p1 I8 s& Y3 | pType.size = sizeof(fTable)/sizeof(StateTable);0 Q; o* ~! [6 u7 h. ^3 }9 B 6 `' z; @9 F2 I% u3 W printf("init state:%d\n\n",pType.curState);& h, d; W0 u- g$ {) _9 W5 J2 P+ m fsmEventHandle(&pType,event_1);3 o$ u0 s# A& O( j3 x. M! }) _ printf("state:%d\n\n",pType.curState);& [- @4 _7 p7 v& q- Y2 @3 X fsmEventHandle(&pType,event_2);3 E; i* c" C6 _$ G6 X) F! F/ ?4 d printf("state:%d\n\n",pType.curState);9 t" y% g) A4 n$ f5 [ + j' F, J. m! M! w2 z8 e+ _3 w fsmEventHandle(&pType,event_3);" E/ _* E9 n& K# t/ V d8 v printf("state:%d\n\n",pType.curState); fsmEventHandle(&pType,event_4); printf("state:%d\n\n",pType.curState); ! O+ L( {* J% F! t3 V& ? fsmEventHandle(&pType,event_2);$ i0 f$ f* y4 Z* _+ J2 O printf("state:%d\n\n",pType.curState); return 0;% d V5 i" T0 h- U( w } 编译结果 ![]() 总结 使用函数指针实现的FSM的过程还是比较费时费力的,但是这一切相对一大堆的if/else、switch/case来说都是值得的,当你的程序规模变得越来越大的时候,基于这种表结构的状态机,维护程序起来会清晰很多。 |