C语言状态模式

先声明,这里的状态模式和设计模式里的状态不太一样。

一般嵌入式里写状态机都会使用到switch语句,每种case就是每个状态。好处就是简单易懂,坏处就是switch内代码量比较大,容易错。所以参考了设计模式里的写法,设计以下函数的写法:

首先是StateMode.h文件里函数声明和结构体定义,结构体里保存的是一个State 用于储存当前状态和数据结构体,这个数据结构体是我原打算做为全局变量为整个状态机所使用的,但是实际使用中都没用上,用得到的数据就只有State。

#ifndef __StateMode
#define __StateMode
#include "ViewMode.h"
typedef struct CONTEXT CONTEXT;
typedef struct State State;
typedef void (*StaHandle)(CONTEXT *Context,FUNCDATA *funcdata);
typedef struct State{
    StaHandle handle;
}State;
struct CONTEXT{
    FUNCDATA funcdata;
    State state;
};
void ContextRequest(CONTEXT *context);//函数循环调用
void ContextInit(CONTEXT *context,StaHandle handle);//状态机初始化,设置初始状态
void ContextSetSta(CONTEXT *context,StaHandle handle);//状态机切换
StaHandle ContextGetSta(CONTEXT *context);//得到当前状态
#endif

然后是c文件

#include "StateMode.h"
void ContextRequest(CONTEXT *context){
    if(0 == context)return ;
    if(0 == context->state.handle) return;
    context->state.handle(context,&context->funcdata);//这样实现参数的传递啊
}
void ContextInit(CONTEXT *context,StaHandle handle){
    if(0 == context)return ;
    context->state.handle = handle;
}
void ContextSetSta(CONTEXT *context,StaHandle handle){
    if(0 == context) return;
    if(0 == handle) return;
    context->state.handle = handle;
}
StaHandle ContextGetSta(CONTEXT *context){
    if(0 == context) return 0;
    return context->state.handle;
}

最后是例子c文件


void staA(CONTEXT *context,FUNCDATA *funcdata){
    ContextSetSta(context,staB);//下一个状态
}
void staB(CONTEXT *context,FUNCDATA *funcdata){
    ContextSetSta(context,staC);//下一个状态
}
void staC(CONTEXT *context,FUNCDATA *funcdata){
    ContextSetSta(context,staD);//下一个状态
}
void staD(CONTEXT *context,FUNCDATA *funcdata){
    ContextSetSta(context,staE);//下一个状态
}
void staE(CONTEXT *context,FUNCDATA *funcdata){
    ContextSetSta(context,staA);//下一个状态
}
CONTEXT context;
void tesrt(){
    ContextInit(&context,staA);
    while(1){
        ContextRequest(&context);
    }
}

若用switch语句写会有5个case,多个case语句对效率,代码整洁都有影响,用这种方法适合状态较多下的情况。而且能通过改造StateMode.c里的函数获得便利,比如想得到A状态到B状态的时间,但又想把计时器放到写好的代码里,这时候就可以改造ContextSetSta函数:当状态为A时候开始计时当等到B时停止计时,这样就能获得时间,而且又不会改变应用层代码。

猜你喜欢

转载自blog.csdn.net/qq_16711745/article/details/82156878
今日推荐