C语言利用函数指针+函数指针数组去掉冗长的if-else

函数指针

定义函数指针

int(*p)(int, int);
void(*p)(void);

函数指针数组

定义函数指针数组

typedef void (*p)(void);
const p Box[3] = {fun1,fun2,fun3};

void fun1(void){};
void fun2(void){};
void fun3(void){};

实战代码

应用场景概况

  • 单片机按键扫描,有3个可用按键
  • 用二进制思维,3个可用按键可以映射为8个数字,忽略数字0,也就是有7种不同情况
  • 简单的测试,7种不同的情况,用7个普通的函数做对应的动作
  • 最简单的设计方法是用if,elseif。囊括7个不同分支,但是如果有拓展,就会让代码冗长难读

code

int _beepTime = 0; 
struct rt_semaphore KeyOnSem; //按键有效信号量

//定义函数指针数组
typedef void (*beepBox)(void); 
static const beepBox Box[8] = {NULL,_beep1,_beep2,_beep3,_beep4,_beep5,_beep6,_beep7};

/*
 *      struct BeepStrategy{
 *      int type;
 *      void (*_beep_)(void);
 *      };
 */
struct BeepStrategy Strategy = {
    .type = 0,
    ._beep_ = NULL
};

//入口
void _beepType(void){
    if(_beepTime == 0) return;
    Strategy.type = _beepTime; //这里感觉其实多余了
    Strategy._beep_ = Box[Strategy.type];
    Strategy._beep_();
/*用完之后必须要把这个指针指向NULL,否则会宕机*/
    Strategy.type = 0;
    Strategy._beep_ = NULL;
}
//这个是按键的状态初始化,根据引脚上拉和下拉的情况初始化的
KeyVal Val = {
        .key1 = 1,
        .key2 = 1,
        .keyup = 0
};

//这个函数是实现3个按键输出1~7,把值赋给_beepTime
void _beepmode(KeyVal* val){
    val->key1 = ~val->key1;
    val->key2 = ~val->key2;

    _beepTime |= val->keyup;
    _beepTime <<= 1;
    _beepTime |= val->key2;
    _beepTime <<= 1;
    _beepTime |= val->key1;

    if(_beepTime == 0) return;
    rt_sem_release(&KeyOnSem);
}

//这个rtthread线程,用来检测按键状态
void scankey_task_entry(void* parameter)
{
    while(1)
    {
        Val.key1 = rt_pin_read(_KEY0_);
        Val.key2 = rt_pin_read(_KEY1_);
        Val.keyup = rt_pin_read(_KEYUP_);
        _beepmode(&Val);
        rt_thread_mdelay(200);
    }
}

//这个线程,用来响应按键的结果。用一个信号量永远阻塞,当按键按下并产生有效数据(_beepTime)就释放一个信号让这里运行
void BeepTask_entry(void* parameter){
    rt_sem_init(&KeyOnSem,"KeyOn",0,RT_IPC_FLAG_FIFO);
    while(1){
        rt_sem_take(&KeyOnSem,RT_WAITING_FOREVER);

        _beepType(); //直接调用这个函数,自动就会根据_beepTime的值调用相应的函数
			
        _beepTime = 0; //用完之后要初始化
    }
}

//下面是具体动作
void _beep1(void){
    rt_kprintf("beep1~~~\r\n");
    rt_pin_write(_BEEP_,PIN_HIGH);
    rt_thread_mdelay(100);
    rt_pin_write(_BEEP_,PIN_LOW);
    rt_thread_mdelay(100);
}

void _beep2(void){
    rt_kprintf("beep2~~~\r\n");
    rt_pin_write(_BEEP_,PIN_HIGH);
    rt_thread_mdelay(200);
    rt_pin_write(_BEEP_,PIN_LOW);
    rt_thread_mdelay(200);
}

void _beep3(void){
    rt_kprintf("beep3~~~\r\n");
}

void _beep4(void){
    rt_kprintf("beep4~~~\r\n");
    rt_pin_write(_BEEP_,PIN_HIGH);
    rt_thread_mdelay(500);
    rt_pin_write(_BEEP_,PIN_LOW);
    rt_thread_mdelay(500);
}

void _beep5(void){
    rt_kprintf("beep5~~~\r\n");
}

void _beep6(void){
    rt_kprintf("beep6~~~\r\n");
}

void _beep7(void){
    rt_kprintf("beep7~~~\r\n");
}

ps:要是不定序的数字或者字符串怎么办

  • 多用一个数组做匹配,然后返回下标吧

总结

  • 这样拓展的时候就直接拓展数组,并实现相应的函数就可以了。
  • 但是我认为嵌入式依赖硬件平台,资源比起纯软件开发少多了,未来拓展的可能性和规模也不如互联网的需求大。
posted @ 2020-10-07 16:11  JoyooO  阅读(252)  评论(0编辑  收藏  举报