我是靠谱客的博主 甜蜜机器猫,最近开发中收集的这篇文章主要介绍C语言状态机学习笔记一,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

出处:http://www.cnblogs.com/tangerious/p/4565833.html

状态机的好处不用多说,自己百度去,但传统的编程模式,无论是C语言,或是硬件FPGA的Verilog都是采用switch-case
结构,硬件的还好说,是并行的,但如果是C语言实现状态机则可能需要对每个case进行判断,状态少比如几个可能没什
么效率之类的问题,但状态多几十个上百个呢,那么就需要进行上百次的判断是否匹配,毫无疑问效率很低,切每次的
状态切换时间也不确定。那么有没有一种好的实现模式不用switch-case结构呢?下面我来为C语言状态机的实现建立一
个最优模式。
实现
前面说了一堆装bi的废话,下面进入正题,前段时间研究了下函数式编程,发现C语言的循环结构完全可以用尾递归(不
懂百度)实现,最后C就只剩下唯有if和switch还不能用函数式编程实现,而今天要讲的状态机模式就是用函数式编程实
现switch-case,那么switch-case其实可以看做一种查找的跳转,我们知道C语言中goto可以实现跳转,那么还有什么可
以实现跳转呢,答案是函数调用,但是又需要如何实现指定的函数调用呢,难道要用if判断,显然没什么意义,那么又
没有比if判断(如果上百次判断)更高效的东西呢?有人已经想到是查表,如果将查表和函数调用结合,那么就是函数
指针数组的应用了! 
上代码!首先定义一个函数指针类型,为什么要带void *的参数后面会说:


typedef unsigned char State;
typedef State(*Procedure)(void *);
这样就可以方便地定义一个函数指针数组:


Procedure Steps[] = { step_init, step_count, step_done, step_default };


step_init,step_count等是函数名,再定义状态:


enum states{ s_init, s_count, s_done, s_default };


枚举定义对应着{0,1,2,3},有了这些再状态机联系那么可以想到,数组的索引就是状态定义,上核心代码,两行(简单


吧!关键是想到):


void BestStateMachine(void * invar)
{
    static State NS = s_init; //定义下一状态
    NS = Steps[NS](invar);
}


static的变量NS在每次BestStateMachine调用会得到维护,我们只需再每Steps返回下一个状态并保存到NS中可以实现状


态的保存和切换。再说说为什么要加个void*的参数,状态机一般有很多自身变量的维护,而且对于mealy状态机还需根


据输入判断,因为函数调用返回是不保留局部变量的,那么就需要将变量传递来实现更改和保存,之所以只用了一个


void*参数是因为,如果需要保存和传递的变量很多,直接传递会在调用函数是浪费大量的栈空间,且效率低下,采用这


种模式,你可以将变量用一个结构体封装,然后将结构体指针传递给void *的形参,再函数内部再强制转换即可使用结


构体内部的变量。现在你已经在嘀咕这作者真啰嗦,好上实例代码,就是一个简单的计数器(以前学状态机都从计数器


开始),在计数完成打印信息:
#include<stdio.h>
typedef unsigned char State;
typedef State(*Procedure)(void *);
enum states{ s_init, s_count, s_done, s_default };//状态定义
typedef struct _SM_VAR  //对状态机参数封装
{
    int cnt;
}SM_VAR;
State step_init(void * arg)//初始化
{
    SM_VAR *p = (SM_VAR *)arg;
    p->cnt = 0;
    printf("CS:init ;cnt=%d;NS:countn", p->cnt);
    return s_count;
}
State step_count(void * arg)//计数
{
    SM_VAR *p = (SM_VAR *)arg;
    if (p->cnt < 3){
        p->cnt+=1;
        printf("CS:count;cnt=%d;NS:countn", p->cnt);
        return s_count;
    }
    else{
        printf("CS:count;cnt=%d;NS:donen", p->cnt);
        return s_done;
    }
}
State step_done(void * arg)//计数完成
{
    SM_VAR *p = (SM_VAR *)arg;
    printf("CS:done ;cnt=%d;NS:initn", p->cnt);
    return s_init;
}
State step_default(void * arg)//错误过程
{
    SM_VAR *p = (SM_VAR *)arg;
    printf("Wrong Staten");
    return s_init;
}
Procedure Steps[] = { step_init, step_count, step_done, step_default };


void BestStateMachine(void * invar)
{
    static State NS = s_init; //定义下一状态
    NS = Steps[NS](invar);
}
int main(void)
{
    SM_VAR var;
    int i;
    for (i = 0; i <8; i++){//给状态机8个周期的时钟驱动
        BestStateMachine(&var);
    }
    return 0;
}


最后在VS2013上调试如下:


CS:init ;cnt=0;NS:count
CS:count;cnt=1;NS:count
CS:count;cnt=2;NS:count
CS:count;cnt=3;NS:count
CS:count;cnt=3;NS:done
CS:done ;cnt=3;NS:init
CS:init ;cnt=0;NS:count
CS:count;cnt=1;NS:count
请按任意键继续. . .

最后

以上就是甜蜜机器猫为你收集整理的C语言状态机学习笔记一的全部内容,希望文章能够帮你解决C语言状态机学习笔记一所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(37)

评论列表共有 0 条评论

立即
投稿
返回
顶部