一个结构和联合“妙用”分析

mac2022-06-30  72

 在《NiosII那些事儿》串口实验中,有这样一段程序:

sopc.h

....... typedef struct { //接收寄存器 union { struct { volatile unsigned long int RECEIVE_DATA :8; volatile unsigned long int NC :24; }BITS; volatile unsigned long int WORD; }RXDATA; //发送寄存器 union { struct { volatile unsigned long int TRANSMIT_DATA :8; volatile unsigned long int NC :24; }BITS; volatile unsigned long int WORD; }TXDATA; //状态寄存器 union { struct { volatile unsigned long int PE :1; volatile unsigned long int FE :1; volatile unsigned long int BRK :1; volatile unsigned long int ROE :1; volatile unsigned long int TOE :1; volatile unsigned long int TMT :1; volatile unsigned long int TRDY :1; volatile unsigned long int RRDY :1; volatile unsigned long int E :1; volatile unsigned long int NC :1; volatile unsigned long int DCTS :1; volatile unsigned long int CTS :1; volatile unsigned long int EOP :1; volatile unsigned long int NC1 :19; }BITS; volatile unsigned long int WORD; }STATUS; //控制寄存器 union { struct { volatile unsigned long int IPE :1; volatile unsigned long int IFE :1; volatile unsigned long int IBRK :1; volatile unsigned long int IROE :1; volatile unsigned long int ITOE :1; volatile unsigned long int ITMT :1; volatile unsigned long int ITRDY :1; volatile unsigned long int IRRDY :1; volatile unsigned long int IE :1; volatile unsigned long int TRBK :1; volatile unsigned long int IDCTS :1; volatile unsigned long int RTS :1; volatile unsigned long int IEOP :1; volatile unsigned long int NC :19; }BITS; volatile unsigned long int WORD; }CONTROL; //波特率分频器 union{ struct { volatile unsigned long int BAUD_RATE_DIVISOR :16; volatile unsigned long int NC :16; }BITS; volatile unsigned long int WORD; }DIVISOR; }UART_STR; ......

这个程序用得很巧妙,看起来十分复杂。

【原理】

(1) 联合体中的成员共用一个内存,初始化操作对第一个成员进行;

(2) 位段将一个类型变量拆分为不同的位,从而对同一个类型定义的变量可以方便的进行位操作,相当于给位取别名

【分析】

(1) 首先建立了一个类型名为UART_STR的结构体,注意typedef的使用;

(2) 该结构体中包含了5个联合体,分别为RXDATA、TXDATA、STATUS、CONTROL、DIVISOR;

(3) 每个联合体中包含了一个使用位段的BITS和一个WORD,注意都是4字节,32bit

由【原理1】可知,BITS和WORD共用了一个内存,所以每个联合体只占了1个unsigned int,即4字节,对BITS操作时,WORD的取值也会改变,反之亦然。一方面节省了内存空间,另一方面,对BITS进行操作和对WORD操作是相当的,好像是给变量取了个别名。对BITS操作可以方便的实现各个位的操作,而WORD可以实现整体的操作。

【举例】

uart.c

(1) 利用BITS对单个位进行操作

static int uart_send_byte(unsigned char data) { UART->TXDATA.BITS.TRANSMIT_DATA=data; while(!UART->STATUS.BITS.TRDY); return 0; }

(2) 利用WORD对整体进行操作

static int set_baudrate(unsigned int baudrate) { UART->DIVISOR.WORD=(unsigned int)(ALT_CPU_FREQ/baudrate+0.5); return 0; }

 【位段】

位段的使用方便了对各位进行操作。但位段也有难以移植的缺陷。以32位机器为例。在PC机上,位段的储存顺序是从右向左存储的。而Macintosh上却是自左向右存储的。这就会造成一些问题。现有一个16位的结构。分别用BITS(位段结构,如示例)和WORD(unsigned int)表示。在PC机上进行操作时,BITS和WORD均存储在最低16位。但在Macintosh上,BITS被装入高16位,而WORD被装入低16位。这时,对BITS和WORD操作就不是等效的。

 

转载于:https://www.cnblogs.com/J2EEPLUS/archive/2011/12/26/2487967.html

相关资源:数据结构与算法(Java 描述)-邓俊辉
最新回复(0)