这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» 综合技术» 基础知识» 教你3种管理C程序中标志位的方法

共6条 1/1 1 跳转至

教你3种管理C程序中标志位的方法

高工
2022-11-22 08:58:26 打赏

在嵌入式开发中,难免会涉及到非常多的标志位处理,特别是玩单片机、裸机开发的朋友,比如跟一些模块配合联调会遇到各种信号是否到位、成功等等状态,而这些信号大多都是bool类型,1个bit即可进行标识。

当然,如果仅仅是几个标志,直接拿个uint8_t的整形来进行标识也不会影响什么,但如果特别多的话似乎就比较废RAM了。然而,为了更好的管理这些标志位等,有个如下几种方式供大家更好的管理这些标志位 :

1

位域直接标识

采用位域是管理这些标志位比较直接且方便的方式,代码如下所示:

1typedef union _tag_SystemFlag
2{
3uint16_t all;
4struct
5{
6uint16_t Run :1;
7uint16_t Alarm :1;
8uint16_t Online :1;
9uint16_t TimerOver :1;
10uint16_t Reserver :12;
11}bit;
12
13} uSystemFlag;
14
15uSystemFlag unSystemFlag;
16
17int main(int argc, char *argv[]) {
18
19unSystemFlag.all =0x00;//系统标志清除
20
21unSystemFlag.bit.Run =1;//置位
22unSystemFlag.bit.Alarm =1;
23unSystemFlag.bit.Online =1;
24unSystemFlag.bit.TimerOver =1;
25
26unSystemFlag.bit.Run =0;//清零
27unSystemFlag.bit.Alarm =0;
28unSystemFlag.bit.Online =0;
29unSystemFlag.bit.TimerOver =0;
30
31return0;
32}

这些标志位的操作无非就是置位、清零,以及读取三种方式。

但如代码中这样的操作方式在语句或语义表达上还是不够直观。

我经常谈到,代码可以不写注释,不过你的每个变量、函数名称等需要足够的直观,所以很多朋友习惯把这些标志封装起来。

2

枚举+移位

为了更好的表达一般会对标志位进行进一步的封装,如下代码所示:

1typedef enum _tag_Flag {
2cEmRun =0,
3cEmAlarm,
4cEmOnline,
5cEmTimerOver
6}emSystemFlag;
7
8uint16_t SystemFlag ;
9//置位
10voidSetFlag(emSystemFlag flag)
11{
12SystemFlag |= ((uint16_t)0x01) << flag;
13}
14//清除
15voidClrFlag(emSystemFlag flag)
16{
17SystemFlag &= ~(((uint16_t)0x01) << flag);
18}
19//获得状态
20uint8_t GetFlag(emSystemFlag flag)
21{
22return(((SystemFlag & (((uint16_t)0x01) << flag)) !=0)?true:false);
23}
24
25int main(int argc, char *argv[]) {
26
27SetFlag(cEmAlarm);
28
29if(GetFlag(cEmAlarm) ==true)
30{
31printf("ClrFlag\r\n");
32ClrFlag(cEmAlarm);
33}
34else
35{
36printf("SetFlag\r\n");
37SetFlag(cEmAlarm);
38}
39return0;
40}

当然,封装成函数是相对比较耗时的,不过代码也会更加的易懂,如果确实容忍不了函数封装带来的时间消耗,把函数修改为宏代码片段或者内敛函数(前提是编译器支持)也是可行的。

3

宏列表

或许这里才是本文的重中之重~

前跟大家介绍过,用宏自动化的生成各种代码片段,以使得代码更加的紧凑。当然可读性会相对降低一点,但对于重复性代码就不需要太多考虑了。

1#include
2#include
3
4typedef unsigned char uint8_t;
5typedef unsigned int uint16_t;
6typedef signed char int8_t;
7typedef int int16_t;
8
9#definetrue1
10#definefalse0
11
12
13//宏列表
14#define TAG_LIST(tag) \
15tag(Run)\
16tag(Alarm)\
17tag(Online)\
18tag(TimerOver)
19
20
21//枚举处理
22#define DEFINE_TAG(_tag) _tag,
23enum Flag {
24None =0,
25TAG_LIST(DEFINE_TAG)
26EmMAX
27};
28#undef DEFINE_TAG
29
30//位定义变量
31uint16_t SysFlag =0x0000;
32
33
34//通用方法定义
35uint8_t GetFlags(uint16_t mask)
36{
37return((SysFlag & mask) !=0)?true:false;
38}
39
40voidSetFlags(uint16_t mask)
41{
42SysFlag |= mask;
43}
44
45voidClrFlags(uint16_t mask)
46{
47SysFlag &= ~mask;
48}
49
50
51//自动生成三类函数定义
52#define FLAG_Operater(flag) \
53uint8_t get##flag() {\
54returnGetFlags(1<< flag);\
55}\
56voidset##flag() {\
57SetFlags(1<< flag);\
58}\
59voidclr##flag() {\
60ClrFlags(1<< flag);\
61}
62
63//反向函数关联
64TAG_LIST(FLAG_Operater)
65
66int main(int argc, char *argv[]) {
67
68setRun();
69setAlarm();
70
71if(getAlarm() ==true)
72{
73printf("set \r\n");
74}
75else
76{
77printf("clr \r\n");
78}
79
80return0;
81}

如果以前有过类似代码处理的朋友,应该看这段代码还是比较轻松的吧,如果有点生疏,可以一层一层展开了解。

其主要的功能是,通过宏替换和代码拼接符号,自动的生成通用的代码片段。这样做的好处是,不再需要我们在代码中定义一大堆setflag、clrflag、getflag等函数。

通过上面的代码当我们向TAGLIST宏中添加一个标识符,即可生成一系列相关的操作函数等。

这样一方面可以及简化代码,同时也能避免一些人工编码带来的错误。





关键词: 管理 C程序 标志

专家
2022-11-22 09:53:14 打赏
2楼

感谢分享,学习了


高工
2022-11-29 16:51:18 打赏
3楼

感谢分享


高工
2022-12-20 23:07:31 打赏
4楼

感谢分享


专家
2022-12-20 23:08:52 打赏
5楼

感谢分享


专家
2022-12-21 00:07:26 打赏
6楼

谢谢分享


共6条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]