栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

状态机编程思维学习笔记(C语言)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

状态机编程思维学习笔记(C语言)

前言

不摸鱼摆烂的第一天

目录
  • 前言
  • C语言面对对象特性引入
      • 函数指针
      • 结构体中套用函数指针
      • 宏定义中##纯替换
  • 状态机概念
  • 状态机实现
  • 后文

C语言面对对象特性引入

众所周知,C++是由C语言编写而成,因此,C语言也可以实现一定程度的面对对象编程,接下来为引入状态机的程序,我们先来介绍几个不常用的C语言用法。

函数指针

众所周知,指针是C语言的灵魂,它不仅可以指向各种变量和自己,并且可以指向函数。
先来看正常的C函数

void function_name(void *arg);

这个函数,我们将参数设置为void形式方便后续添加参数。

我们可以根据上方函数声明创建函数指针变量
由于优先级问题,将名称括起来并加上星号

void (*P_function)(void *arg);

这样,在调用时,就可以

P_function = function_name;


(*P_function)( 填入对应参数 );

当然,函数的返回值类型可以任意指定,但是上下必须保持一致。

扩展
在上面为什么要使用void* 作为参数呐?
因为如果使用了void*,我们就可以在函数中将它转化为任意类型的变量指针
只需要使用强制类型转换,就可以轻而易举的达到我们的目的。

void function_name(void *arg)
{
	
    int *need_arg= (int *)arg;
    ...
}
结构体中套用函数指针

前面说了函数指针,如果我们能在结构体中添加函数指针项,就可以实现类似C++一样的面对对象的形式。

struct func_struct{
    int n;
    void (*P_func)(int n);
};


struct func_struct func;
func->P_func( 100 );
宏定义中##纯替换

宏定义也可以使用一些变量替换,这样方便我们编程,而实现的方法。

#define NUM(n)  (num_##n)

例如:
NUM(1) 替换为 num_1
NUM(2) 替换为 num_2
NUM(3) 替换为 num_3
状态机概念

要说状态机的概念就得从实例来讲。
比如说一个控制一个发光二极管。

由图可以知道,二极管有两种状态,亮和灭,分别对应IO口的两种动作,高电平和低电平。从这里出发,可以得出状态机的4个要素

  • 状态:即灯的亮状态和暗状态。
  • 事件:使灯亮的触发条件,比如IO开高电平。
  • 动作:事件发生后执行的动作,这里即为灯亮,但是更为复杂的情况需要一个函数实现,比如向串口发送一个当前状态的报告。
  • 变换:灯亮到灯暗。可以用一个结构体表示所有变换因素。

我个人有个不太恰当的理解,变换作为一个整体的系统(传函),状态就是我们的输出,事件就是输入与触发,动作自然就是输出状态后的响应。

状态机实现

构建一个简单的三层状态机系统
有三个状态,四个事件,并且动作设计为可以现实当前所处状态。

之后构建状态迁移表

对状态机的变换结构体,事件和状态进行编写。

#ifndef _STATE_H
#define _STATE_H

typedef enum _sta_{
    state1,state2,state3
}State;

typedef enum _evt_{
    evt_1t2,evt_2t3,evt_3t1,evt_1t3
}Event;

typedef struct {
    State curState; //当前状态
    Event eventId;  //事件ID
    State nextState;//下个状态
    void (*action)(void *arg);//回调函数(动作函数),事件发生后,调用对应的回调函数
}StateTransform;

#endif  

再写出动作函数

void action_callback(void *arg)
{
	
    StateTransform *statTran = (StateTransform *)arg;
    
    printf("状态由%d由%d",statTran->curState+1,statTran->nextState+1);
}

构建状态迁移矩阵
此处每个结构体对应数组代表迁移列表中的列。

StateTransform stateTran_1[] = {
        {state1,evt_1t2,state2,action_callback},//每一行代表一个结构体变量
        {state1,evt_2t3,state1,NULL},
        {state1,evt_3t1,state1,NULL},
        {state1,evt_1t3,state3,action_callback},
};

StateTransform stateTran_2[] = {
        {state2,evt_1t2,state2,NULL},
        {state2,evt_2t3,state3,action_callback},
        {state2,evt_3t1,state2,NULL},
        {state2,evt_1t3,state2,NULL},
};

StateTransform stateTran_3[] = {
        {state3,evt_1t2,state3,NULL},
        {state3,evt_2t3,state3,NULL},
        {state3,evt_3t1,state1,action_callback},
        {state3,evt_1t3,state3,NULL},
};

构建完整状态迁移表后,创建一个全局的变量作为当前状态
即 State GlobleCurState;
之后,进行简单的查表即可。
也就是说,根据当前状态和输入的事件,在状态迁移表中查询下一个状态和动作响应并执行。

void event_happen(Event event) //输入事件
{
    switch (GlobleCurState) {
        case state1:
            do_action(&STATETRANS(1)[event]); //执行对应动作
            break;
        case state2:
            do_action(&STATETRANS(2)[event]);
            break;
        case state3:
            do_action(&STATETRANS(3)[event]);
            break;
    }
}

void do_action(StateTransform *stateTran)
{
    //状态迁移
    GlobleCurState = stateTran->nextState;
    //调用回调
    if(stateTran->action == NULL)
    {
        printf("Without Action!nr");
    }
    else
    {
        stateTran->action((void *)stateTran);
    }
}

最后进行简单测试

#define ENTRY_STATE state1
int main() {
    GlobleCurState = ENTRY_STATE;
    State lastState = GlobleCurState;
    Event User_Event;
    printf("当前状态为state%dn",GlobleCurState);
    while(1)
    {
        scanf("%d",&User_Event);
        if(User_Event == -1)
            break;
        event_happen(User_Event);
        printf("当前状态为state%dn",GlobleCurState+1);
    }

    return 0;
}

参考
什么是状态机?用C语言实现进程5状态模型 作者:一口Linux.
谈谈单片机编程思想——状态机 作者:轻松学C语言.


后文

不得不说,在家太舒服了。。。由于疫情不开学,天天摸鱼,啥也没干,我知道摸鱼不对可是就是停不下来哼哼啊啊啊啊啊啊啊。

但是快开学了,压力在前,就真不能摸了。。。 Orz

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/302371.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号