C语言中使用用户建立数据类型时会接触结构体、共用体、枚举类型等,这些常见的类型在程序设计中实现功能常常会有很大的好处,也更能体现开发人员的专业性,也能使程序结构清晰,严谨。下面就以在嵌入式软件设计为例,根据实际问题说说枚举类型和结构体、共用体的应用。
在此之前还是先看看一下这些常见类型的使用情况。
结构体
struct 结构名
{
成员表列
}
struct {
int a;
char b;
double c;
} s1;
或者
struct SIMPLE{
int a;
char b;
double c;
};
共用体
union 共用体类型名
{
成员列表
}
typedef union{
char c;
int a;
int b;
}Demo;
枚举类型
enum 枚举名{ 枚举值表 };
enum weekday{ sun,mou,tue,wed,thu,fri,sat };
enum weekday a,b,c;
枚举常用switch-case开关语句联合使用。
以上为基本用法,下面介绍这些类型的实际和综合应用。
实例背景: 设计一个数据采集系统,能够对电网众多数据进行采集并通过总线(RS485)传输。
设备:数据采集芯片、CPU等
对硬件部分就不详细说明了,软件主要是对芯片驱动(包括LCD driver等),以及通信协议等。下面就介绍这些常用模块中如何使用结构体、共用体、枚举等较好实现模块功能。
先说枚举类型:
枚举主要是可以任意给枚举元素赋值
enum {
SYS_OK = 0,
SYS_COMM_ERROR,
SYS_COMM_RETRY,
SYS_COMM_WAIT,
SYS_REBOOT,
SYS_OVER_THRESHOLD,
SYS_UART_DEVICE_ID_ERROR,
SYS_DEVICE_OPEN_CIRCUIT,
SYS_DEVICE_SHORT_CIRCUIT,
SYS_DEVICE_OVER_THRESHOLD,
};
以上枚举类型中可以区分不同状态,这样根据枚举元素进行索引就可以判断系统处于哪一种状态中。下面是LCD驱动的一种写法:
enum
{
ComplexDigtalNumFirst_I = 0,
ComplexDigtalNumFirst_F = 0,
ComplexDigtalNumFirst_G = 0,
ComplexDigtalNumFirst_M = 0,
ComplexDigtalNumFirst_N = 1,
ComplexDigtalNumFirst_E = 1,
ComplexDigtalNumFirst_A = 2,
ComplexDigtalNumFirst_J = 2,
ComplexDigtalNumFirst_K = 2,
ComplexDigtalNumFirst_B = 2,
ComplexDigtalNumFirst_L = 3,
ComplexDigtalNumFirst_C = 3,
ComplexDigtalNumFirst_D = 3,
}
以上代码片段可以表示地址,也可以表示其他的含义,其实说简单点枚举类型就是功能划分比较清楚一点,还有就是写出来的程序比较规范一些,关键还是对数字的索引,但是每一个数字可以表示不同的含义,数字可以相同,使用起来比较灵活,在于使用者如何进行功能划分了。
结构体的使用
先看看STM32库函数中关于结构体的使用:
typedef struct
{
vu32 CRL;
vu32 CRH;
vu32 IDR;
vu32 ODR;
vu32 BSRR;
vu32 BRR;
vu32 LCKR;
}
GPIO_TypeDef;
typedef struct
{
vu32 EVCR;
vu32 MAPR;
vu32 EXTICR[4];
}
AFIO_TypeDef;
在数据通信时,如果数据较多我们可以将很多数据打包发送,这时候结构体使用起来是很方便的:
typedef struct {
short year;
unsigned char month;
unsigned char day;
unsigned char hour;
unsigned char minute;
}Date_S;
typedef struct {
int A_I;
int B_I;
int C_I;
int N_I;
int A_DMD;
int B_DMD;
int C_DMD;
int N_DMD;
int A_PECK;
int B_PECK;
int C_PECK;
int N_PECK;
Date_S A_PEAK_TIME;
Date_S B_PEAK_TIME;
Date_S C_PEAK_TIME;
Date_S N_PEAK_TIME;
int I_UNBAL;
int U_A_B;
int U_B_C;
int U_A_C;
int UNBAL_ABC;
int U_A_N;
int U_B_N;
int U_C_N;
int UNBA_ABCN;
int PQS_KW;
int PQS_KVAR;
int PQS_KVA;
}
这样对于数据发送检验以及接收后拆包进行数据处理都挺方便,特别是使用结构指针时更灵活了。使用C语言写实际应用程序时,结构体的使用特别多,不管是游戏还是一些实用程序里面,包括linux底层(用C来写),因为结构体里面可以是结构体、共用体等其他的类型,下面就给出了一个实际应用中结构体与共用体联合使用的实例:
union Package{
struct Packet_base package_base;
struct PACKDATA_Energy package_energy;
};
struct Frame{
unsigned char head;
unsigned char cmd;
unsigned char len;
union Package package;
unsigned char seq;
unsigned short check;
unsigned char tail;
};
上面代码段是一段RS485通信进行数据传输的主要实现过程,考虑到数据长度问题,但是发送的数据包长度可能不同,每次只能发送一个数据包,如何处理这个问题呢?此处用共用体较好解决了这个问题,共用体所占用的内存只能是共用体中的内存最大的那个元素,比如说数据包Packet_base package_base、PACKDATA_Energy package_energy所占内存大小不一样,一个128Bytes另外一个200Bytes,最终加上head和tail以及校验和、数据包一起发送的时候长度就是变动的。如果不使用union,那么发送的数据长度局势固定的,可能会浪费内存,效率低,甚至还会出现无用错误数据,接收端不好处理。
采用以上结构体用union,union内又使用其他的结构体方式能够灵活处理数据传输。关于结构体、共用体、枚举类型更多的使用方法可以参看一些官方库函数。