C语言枚举、结构体、共用体综合应用实例

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;// = 0x5A;
    unsigned char cmd;// = 0x64;
    unsigned char len; //= 5;
    union Package package;
    unsigned char seq; //= 0;
    unsigned short check;
    unsigned char tail;// = 0xF0;
};

上面代码段是一段RS485通信进行数据传输的主要实现过程,考虑到数据长度问题,但是发送的数据包长度可能不同,每次只能发送一个数据包,如何处理这个问题呢?此处用共用体较好解决了这个问题,共用体所占用的内存只能是共用体中的内存最大的那个元素,比如说数据包Packet_base package_base、PACKDATA_Energy package_energy所占内存大小不一样,一个128Bytes另外一个200Bytes,最终加上head和tail以及校验和、数据包一起发送的时候长度就是变动的。如果不使用union,那么发送的数据长度局势固定的,可能会浪费内存,效率低,甚至还会出现无用错误数据,接收端不好处理。

采用以上结构体用union,union内又使用其他的结构体方式能够灵活处理数据传输。关于结构体、共用体、枚举类型更多的使用方法可以参看一些官方库函数。

你可能感兴趣的:(嵌入式系统)