状态机


  理论上分为有限状态机和无限状态机,但无限状态机的状态集Q是无限的,这蕴含着转移函数有无限多的映射,因此它是一种思考理论上的模型。

  状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机的内在因果关系的考虑。“现态”和“条件”是因,“动作”和“次态”是果。详解如下:

现态:是指当前所处的状态。
条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。

有限状态机FSM分为两大类

若输出只和状态有关而与输入无关,则称为Moore状态机
输出不仅和状态有关而且和输入有关系,则称为Mealy状态机

作为两年以上的程序老鸟,状态机的写法理应成熟简洁。但往往在快速完成的要求下总会选用标记位和switch、if-else快速构成状态机逻辑。俗话说磨刀不误砍柴工,地基决定上层建筑,花点时间把每一个知识点框架整理一遍,将来你的摩天大楼建造将会更快更稳。以下两个是一些典型的c语言状态机,写法不一样,但是蕴含的思维是大同小异的,第二个更符合大多数场合。

处理按键引发的多状态切换

转载自https://blog.csdn.net/qq_35579835/article/details/106536745


/***********************************************
1、定义状态接口,以MP3的状态接口为例,每种状态下都可能发生
两种按键动作。
************************************************/

typedef struct State{
  void (* stop)();
  void (* palyOrPause)();
}State;


/***********************************************
2、定义系统当前状态指针,保存系统的当前状态
************************************************/

State * pCurrentState;


/***********************************************
3、定义具体状态,根据状态迁移图来实现具体功能和状态切换。
************************************************/

void ignore();
void startPlay();
void stopPlay();
void pausePlay();
void resumePlay();

//空闲状态时,stop键操作无效,play/pause会开始播放音乐
State IDLE = {
  ignore,
  startPlay
};

//播放状态时,stop键会停止播放音乐,play/pause会暂停播放音乐
State PLAY = {
  stopPlay,
  pausePlay
};

//暂停状态时,stop键会停止播放音乐,play/pause会恢复播放音乐
State PAUSE = {
  stopPlay,
  resumePlay
};

void ignore()
{
  //空函数,不进行操作
}

void startPlay()
{
  //实现具体功能
  printf("开始播放音乐
");
  //进入播放状态
  pCurrentState = &PLAY;
}
void stopPlay()
{
  //实现具体功能
  printf("停止播放音乐
");
  //进入空闲状态
  pCurrentState = &IDLE;
}

void pausePlay()
{
  //实现具体功能
  printf("暂停播放音乐
");
  //进入暂停状态
  pCurrentState = &PAUSE;
}

void resumePlay()
{
  //实现具体功能
  printf("恢复播放音乐
");
  //进入播放状态
  pCurrentState = &PLAY;
}


/***********************************************
4、定义主程序上下文操作接口,主程序只关心当前状态,不关心状态之间
是怎么变化的。
************************************************/

void onStop();
void onPlayOrPause();

State context = {
  onStop,
  onPlayOrPause
};

void onStop(State *pThis)
{
  pCurrentState->stop(pThis);
}

void onPlayOrPause(State *pThis)
{
  pCurrentState->palyOrPause(pThis);
}


/***********************************************
5、初始化系统当前状态指针,其实就是指定系统的起始状态
************************************************/

void init()
{
  pCurrentState = &IDLE;
}

/***********************************************
6、主程序通过上下文操作接口来控制系统当前状态的变化
************************************************/
void main()
{
  init();
  context.palyOrPause();//播放
  context.palyOrPause();//暂停
  context.palyOrPause();//播放
  context.stop();//停止
}


由于某个事件触发的状态切换

转载自https://www.jianshu.com/p/917c0fb8778b

/*1.定义状态数据的枚举类型*/
enum year_state
{
    SPRING = 1,
    SUMMER,
    AUTUMN,
    WINTER
};

/*2.定义事件的枚举类型*/
enum year_event
{
    EVENT1 = 1,
    EVENT2,
    EVENT3,
    EVENT4,
};

/*3.定义状态表的数据类型*/
typedef struct FsmTable_s
{
    int event;   //事件
    int CurState;  //当前状态
    void (*eventActFun)();  //函数指针
    int NextState;  //下一个状态
}FsmTable_t;

/*4.定义处理函数及建立状态表*/
void spring_thing()
{
    printf("this is spring
");
}
void summer_thing()
{
    printf("this is summer
");
}
void autumn_thing()
{
    printf("this is autumn
");
}
void winter_thing()
{
    printf("this is winter
");
}

FsmTable_t year_table[] =
{
    //{到来的事件,当前的状态,将要要执行的函数,下一个状态}
    { EVENT1,  SPRING,    summer_thing,  SUMMER },
    { EVENT2,  SUMMER,    autumn_thing,  AUTUMN },
    { EVENT3,  AUTUMN,    winter_thing,  WINTER },
    { EVENT4,  WINTER,    spring_thing,  SPRING },
    //add your codes here
};


/*5.状态机类型,及状态机接口函数*/

/*状态机类型*/
typedef struct FSM_s{
    int curState;//当前状态
    FsmTable_t * pFsmTable;//状态表
    int size;//表的项数
}FSM_t;

/*状态机注册,给它一个状态表*/
void FSM_Regist(FSM_t* pFsm, FsmTable_t* pTable)
{
    pFsm->pFsmTable = pTable;
}

/*状态迁移*/
void FSM_StateTransfer(FSM_t* pFsm, int state)
{
    pFsm->curState = state;
}

/*事件处理*/
void FSM_EventHandle(FSM_t* pFsm, int event)
{
    FsmTable_t* pActTable = pFsm->pFsmTable;
    void (*eventActFun)() = NULL;  //函数指针初始化为空
    int NextState;
    int CurState = pFsm->curState;
    int g_max_num = pFsm->size;
    int flag = 0; //标识是否满足条件
    int i;

    /*获取当前动作函数*/
    for (i = 0; i<g_max_num; i++)
    {
        //当且仅当当前状态下来个指定的事件,我才执行它
        if (event == pActTable[i].event && CurState == pActTable[i].CurState)
        {
            flag = 1;
            eventActFun = pActTable[i].eventActFun;
            NextState = pActTable[i].NextState;
            break;
        }
    }


    if (flag) //如果满足条件了
    {
        /*动作执行*/
        if (eventActFun)
        {
            eventActFun();
        }

        //跳转到下一个状态
        FSM_StateTransfer(pFsm, NextState);
    }
    else
    {
        printf("there is no match
");
    }
}

测试程序代码为

/*state.c*/
#include <stdio.h>


enum year_state{
    SPRING = 1,
    SUMMER,
    AUTUMN,
    WINTER
};



enum year_event{
    EVENT1 = 1,
    EVENT2,
    EVENT3,
    EVENT4,
};


typedef struct FsmTable_s{
    int event;   //事件
    int CurState;  //当前状态
    void (*eventActFun)();  //函数指针
    int NextState;  //下一个状态
}FsmTable_t;




void spring_thing()
{
    printf("this is spring
");
}
void summer_thing()
{
    printf("this is summer
");
}
void autumn_thing()
{
    printf("this is autumn
");
}
void winter_thing()
{
    printf("this is winter
");
}


FsmTable_t year_table[] =
{
    //{到来的事件,当前的状态,将要要执行的函数,下一个状态}
    { EVENT1,  SPRING,    summer_thing,  SUMMER },
    { EVENT2,  SUMMER,    autumn_thing,  AUTUMN },
    { EVENT3,  AUTUMN,    winter_thing,  WINTER },
    { EVENT4,  WINTER,    spring_thing,  SPRING },
    //add your codes here
};


typedef struct FSM_s{
    int curState;//当前状态
    FsmTable_t * pFsmTable;//状态表
    int size;//表的项数
}FSM_t;

/*状态机注册,给它一个状态表*/
void FSM_Regist(FSM_t* pFsm, FsmTable_t* pTable)
{
    pFsm->pFsmTable = pTable;
}

/*状态迁移*/
void FSM_StateTransfer(FSM_t* pFsm, int state)
{
    pFsm->curState = state;
}

/*事件处理*/
void FSM_EventHandle(FSM_t* pFsm, int event)
{
    FsmTable_t* pActTable = pFsm->pFsmTable;
    void (*eventActFun)() = NULL;  //函数指针初始化为空
    int NextState;
    int CurState = pFsm->curState;
    int g_max_num = pFsm->size;
    int flag = 0; //标识是否满足条件
    int i;

    /*获取当前动作函数*/
    for (i = 0; i<g_max_num; i++)
    {
        //当且仅当当前状态下来个指定的事件,我才执行它
        if (event == pActTable[i].event && CurState == pActTable[i].CurState)
        {
            flag = 1;
            eventActFun = pActTable[i].eventActFun;
            NextState = pActTable[i].NextState;
            break;
        }
    }


    if (flag) //如果满足条件了
    {
        /*动作执行*/
        if (eventActFun)
        {
            eventActFun();
        }

        //跳转到下一个状态
        FSM_StateTransfer(pFsm, NextState);
    }
    else
    {
        printf("there is no match
");
    }
}


int main()
{
    FSM_t year_fsm;
    FSM_Regist(&year_fsm,year_table);
    year_fsm.curState = SPRING;
    year_fsm.size = sizeof(year_table)/sizeof(FsmTable_t);


    printf("
-------1--init spring------
");
    printf("state:%d
",year_fsm.curState);

    printf("
-------2--spring->summer------
");
    FSM_EventHandle(&year_fsm,EVENT1);
    printf("state:%d
",year_fsm.curState);

    printf("
-------3--summer->autumn------
");
    FSM_EventHandle(&year_fsm,EVENT2);
    printf("state:%d
",year_fsm.curState);

    printf("
-------4--autumn->winter------
");
    FSM_EventHandle(&year_fsm,EVENT3);
    printf("state:%d
",year_fsm.curState);

    printf("
-------5--winter->spring------
");
    FSM_EventHandle(&year_fsm,EVENT4);
    printf("state:%d
",year_fsm.curState);

    printf("
-------6--receive EVENT2 not EVENT1------
");
    FSM_EventHandle(&year_fsm,EVENT2);
    printf("state:%d
",year_fsm.curState);

    return 0;
}