最近看到了有关结构体(struct)和联合体(union)相关的代码,突然发现这两者的结合大有妙用,故做此记录。
1.结构体(struct)
结构体不用多说,C中非常重要的组成部分,一般的声明和定义方式如下:
// 这里先声明一个结构体
struct {
int pro_1;
char pro_2;
float pro_3;
} struct_1;
// 定义一个结构体example
struct struct_1 example = {1, '1', 1.1};
但我更喜欢另一种声明方式:
typedef struct {
int pro_1;
char pro_2;
float pro_3;
} struct_1;
struct_1 example = {1, '1', 1.1};
结构体的用法非常多,在C语言中,结合指针,甚至可以拿来模拟类(class)的用法,这点以后再说。
2.联合体(union)
联合体包含了一系列共用一块内存空间的成员,也被称为共用体。我认为联合体是指针外又一种操作内存的方式,具有高效地访问和修改内存的能力。指针可以直接对其指向的内存进行修改,而不用考虑原本内存上可能定义的变量等是什么。联合体也有类似的作用,其包含的一系列成员之间的关系就类似于指针,它们都互相指向了对方,因此使用一个成员修改内存,其它成员的值也就被修改了。
联合体一般的声明和定义方式如下:
typedef union {
uint8 pro_1[6];
uint16 pro_2[3];
} union_1;
union_1 example;
联合体中的成员所占的内存大小不一定要保持一致,但我们一般就是为了操作同一块内存才使用联合体,所以平时声明的时候,若没有特殊要求,尽量保持一致。
3.结构体+联合体
之前看到的结构体和联合体的组合,在对寄存器的定义中非常的好用。寄存器往往同一段内存会包含复数的作用,即一段2字节16位的内存,可能不仅用作控制位的存放,还可能用作数据的存放,因此使用结构体和联合体组合的方式能有效地定义寄存器之类。
贴一小段RA6M5开发板上的 IOPORT 部分寄存器定义:
typedef struct { /*! R_PORT0 Structure
union {
union {
__IOM uint32_t PCNTR1; /*! Port Control Register 1
struct {
__IOM uint32_t PDR : 16; /*! Pmn Direction
__IOM uint32_t PODR : 16; /*! Pmn Output Data
} PCNTR1_b;
} ;
struct {
union {
__IOM uint16_t PODR; /*!< Output data register
/* ... 代码过长省略 ... */
} ;
union {
__IOM uint16_t PDR; /*!< Data direction register
/* ... 代码过长省略 ... */
} ;
};
};
union {
union {
__IM uint32_t PCNTR2; /*!< Port Control Register 2
struct {
__IM uint32_t PIDR : 16; /*! Pmn Input Data
__IM uint32_t EIDR : 16; /*!Pmn Event Input Data
} PCNTR2_b;
} ;
struct {
union {
__IM uint16_t EIDR; /*! Event input data register
/* ... 代码过长省略 ... */
} ;
union {
__IM uint16_t PIDR; /*! Input data register
/* ... 代码过长省略 ... */
} ;
};
};
/* ... 代码过长省略 ... */
} R_PORT0_Type;
可以看到,最外围是R_POTR0_Type的结构体:
typedef struct {
成员
} R_PORT0_Type;
而内部成员则根据寄存器不同地址段的作用分为了各个联合体,而成员联合体内有嵌套了结构体和联合体:
内部成员:
union_1 {
union_1_1{
XXX
}
struct_1_1{
XXX
}
}
union_2 {
union_2_1{
XXX
}
struct_2_1{
XXX
}
}
其中,为了更好的定义每一位的作用,还使用了位域操作,将一个uint32类型(32位)分为了低16位和高16位,分别定义了两个成员:
struct {
__IOM uint32_t PDR : 16; /*!< [15..0] Pmn Direction
__IOM uint32_t PODR : 16; /*!< [31..16] Pmn Output Data
} PCNTR1_b;
以这种层层嵌套与组合的方式,就可以将一个具有多种功能的寄存器清晰地定义出来。