结构体+联合体+位域的实际使用

您所在的位置:网站首页 结构体与联合体编程题目及答案解析 结构体+联合体+位域的实际使用

结构体+联合体+位域的实际使用

2024-07-08 13:54| 来源: 网络整理| 查看: 265

结构体+联合体+位域的实际使用 结构体位域联合体结合使用

结构体

结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构。 结构体和其他类型基础数据类型一样,例如int类型,char类型只不过结构体可以做成你想要的数据类型。 在实际项目中,结构体是大量存在的。研发人员常使用结构体来封装一些属性来组成新的类型。由于C语言无法操作数据库,所以在项目中通过对结构体内部变量的操作将大量的数据存储在内存中,以完成对数据的存储和操作。 结构体在函数中的作用不是简便,其最主要的作用就是封装。封装的好处就是可以再次利用。让使用者不必关心这个是什么,只要根据定义使用就可以了。 结构体的大小不是结构体元素单纯相加就行的,因为我们现在主流的计算机使用的都是32Bit字长的CPU,对这类型的CPU取4个字节的数要比取一个字节要高效,也更方便。所以在结构体中每个成员的首地址都是4的整数倍的话,取数据元素时就会相对更高效,这就是内存对齐的由来。每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragmapack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

typedef struct { uint32_t cs; /*!< Code and Status*/ uint32_t id; /*!< ID of the message */ uint8_t data[8]; /*!< Data bytes of the CAN message*/ uint8_t length; /*!< Length of payload in bytes */ } can_message_t;

例如上面这个结构体,他的大小通过字节对齐后则为20个字节

/* 以下为结构体成员在内存中的状态 */ cs cs cs cs id id id id data data data data data data data data length null null null

通过结构体能够很好的对数据进行封装。

位域

有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态,用0和1表示足以,也就是用一个二进位。正是基于这种考虑,C语言又提供了一种数据结构,叫做“位域”或“位段”。

位域是操控位的一种方法,通常位域的使用出现在结构体里。

typedef struct { uint8_t type : 4; uint8_t FF_DL_high : 4; uint8_t FF_DL_low; uint8_t data[6]; } IsoTpFirstFrame;

以上的结构体总长度为8个字节,通过位域来确定成员变量所占用的大小。相同的数据类型能够共用一片区域,例如int a:4;int b:4;a与b在内存中则可以存储在一片连续的空间,而int与char的位域则不行。 以上结构体存储的其实是一帧CAN总线的数据,tpye占用四位代表数据的类型,FFDL则是数据的长度,data占用6个字节表示数据。使用位域就能快速解决这种只占用几个bit的问题。

联合体

像结构体一样,联合体(Union)在C语言中是一个用户定义的数据类型,用于保存不同类型的元素。

但它并不占所有成员的内存总和。它只占最大成员的内存,它分享最大成员的内存。 最重要的一点就是联合体成员都是共享同一块内存空间的,怎么做到的呢其实是虚拟地址映射到一块相同的帧数物理地址。

union { IsoTpPciType common; IsoTpSingleFrame single_frame;//单帧 实现方式是结构体里面用位域 IsoTpFirstFrame first_frame;//多帧的首帧 实现方式是结构体里面用位域 IsoTpConsecutiveFrame consecutive_frame;//多帧的传输帧 实现方式是结构体里面用位域 IsoTpFlowControl flow_control;//流控帧 实现方式是结构体里面用位域 IsoTpDataArray data_array; //单纯是一个8个字节unsigned char 的数组 } CanMessage;

以上就是一个联合体,不管是data_array还是flow_control他们都在联合体中,那么他们的地址都是一样的。

结合使用 union { IsoTpPciType common; IsoTpSingleFrame single_frame;//单帧 实现方式是结构体里面用位域 IsoTpFirstFrame first_frame;//多帧的首帧 实现方式是结构体里面用位域 IsoTpConsecutiveFrame consecutive_frame;//多帧的传输帧 实现方式是结构体里面用位域 IsoTpFlowControl flow_control;//流控帧 实现方式是结构体里面用位域 IsoTpDataArray data_array; //单纯是一个8个字节unsigned char 的数组 } CanMessage;

这个联合体真的是非常的神奇啊,当can总线接收到数据后将数据存储到data_array数组中,当传输层要解析这8个字节时则可以直接调用common获取帧的类型,数据类型确定后直接使用single_frame、first_frame、consecutive_frame来进行数据的解析与处理,操作的一直都是同一块内存区域,不需要额外的拷贝操作,对于数据的操作非常方便。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3