0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何设计只有数据字段的结构体

开关电源芯片 来源:程序喵大人 作者:程序喵大人 2021-08-23 09:37 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

之前写过一篇《如何设计一个C++的类》,今天这里继续聊聊如何设计结构体,注意本文不介绍在C++中结构体和类具体有什么区别,本文所说的结构体是指只有数据字段不带任何函数的那种结构体。

当创建结构体的实例时,结构体的数据成员会按其声明的顺序连续存储。然而,这个声明的顺序也是有学问的,顺序不同结构体的大小可能有很大差别,数据成员的访问性能也可能会有很大区别!

这里涉及一个概念:内存对齐。关于内存对齐我之前写过一篇文章:《内存对齐》,这里不深入讨论,只是简单介绍一下。

大多数编译器会对齐数据成员,会以四舍五入地址方式来优化数据的访问,如下表所示。

0c708e52-02f8-11ec-9bcf-12bb97331649.jpg

这种内存对齐可能会在成员大小混合的结构体中产生未使用字节的空洞。

例如:

struct S {

short int a; // 2字节

// 6个空洞

double b; // 8

int d; // 4

// 4个空洞

};

S ArrayOfStructures[100];

这里,在a和b之间有6个未使用的字节,因为b必须从一个能被8整除的地址开始。

最后还有4个未使用的字节空洞。这样做的原因是,数组中S的下一个实例必须从一个能被8整除的地址开始,以便将其b成员以8对齐。

然而,如果改变一下结构体中数据成员声明的顺序,通过将最小的成员放在最后,未使用的字节数可以减少到2:

struct S {

double b; // 8

int d; // 4

short int a; // 2

// 2个空洞

};

S ArrayOfStructures[100];

这种重新排序使结构体变小了8个字节,那整个数组则变小了800个字节。

在此特性上,类和结构体相同。通过重新排序数据成员,结构体对象和类对象通常可以变得更小。如果类至少有一个虚成员函数,则在第一个数据成员之前或最后一个成员之后会有一个指向虚函数表的指针。该指针在32位系统中为4字节,在64位系统中为8字节。

如果不确定结构体或它的每个成员有多大,可以使用sizeof操作符进行一些测试。sizeof操作符返回的值包括对象末尾的任何未使用的字节(内存对齐后的字节数)。

还有一个知识点:

如果数据成员相对于结构体或类开头的偏移量小于128,则访问数据成员的代码会更加紧凑,因为该偏移量可以使用8位有符号的数字来表示。如果相对于结构体或类的开头的偏移量是128字节或更多,那么偏移量必须表示为一个32位数字(指令集在8位到32位之间没有偏移量)。例如:

struct S {

int a[100]; // 400

int b; // 4

int read() { return b; }

};

b成员的偏移量是400。任何通过指针或成员函数访问b字段的代码都需要将偏移量编码为32位数字。如果交换a和b,则两者都可以通过编码为8位有符号数字的偏移量来访问,或者根本不需要偏移量。

这会使代码更紧凑,方便更有效地使用代码缓存。因此,建议在结构或类声明中,大数组和其他大对象排在最后,最常用的数据成员排在前面。如果不能在前128个字节内包含所有数据成员,则将最常用的成员放在前128个字节中。

通过上面两个小知识点可以使得将结构体设计的更小,访问数据成员的速度更快,但是这有时往往会牺牲一些可读性,比如这种结构体:

struct S {

int deskA;

double deskB;

bool deskC;

int chairA;

double chairB;

bool chairC;

};

可能这样修改后结构体会更小:

struct S {

int deskA;

int chairA;

double deskB;

double chairB;

bool deskC;

bool chairC;

};

但是我们一般情况下貌似希望同类的字段放在一起,这样代码可读性更高一些,易于读懂代码。至于这种结构体具体需不需要重新排序,那就需要大家自己权衡啦。

小总结:

注意内存对齐;

128是个槛,常用的数据成员可考虑放在前128字节中,不常用的或大的数据成员可考虑放在后面;

注重性能优化的同时也需要权衡一下代码的可读性。

打完收工。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 存储器
    +关注

    关注

    39

    文章

    7774

    浏览量

    172512
  • 内存
    +关注

    关注

    9

    文章

    3263

    浏览量

    76618
  • 结构体
    +关注

    关注

    1

    文章

    131

    浏览量

    11431

原文标题:如何设计结构体

文章出处:【微信号:gh_3980db2283cd,微信公众号:开关电源芯片】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    抽丝剥茧探穷境!一次数据库JSON字段的深度使用实践

    扩展字段来实现。 通用字段,作用于通用逻辑,所有条线走到相应功能时,会对通用字段读写。而对于个性扩展字段而言,只有用到个性化功能时,才会对个
    的头像 发表于 03-18 11:13 1774次阅读
    抽丝剥茧探穷境!一次<b class='flag-5'>数据</b>库JSON<b class='flag-5'>字段</b>的深度使用实践

    CAN数据传输错误怎么解决?

    电路板总是在数据字段中发送 1 个或一些错误的字节。我预计数据字段是”0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08“。这些错误字节的位置是随机的。我使用 S32DS 版本 3.6.3 和 RTD6.0.0。这是结果。感谢您的帮助。
    发表于 03-16 08:04

    10个例子代码,C语言结构的高级

    当涉及到C语言结构的高级**时,有很多有趣和强大的技巧可以应用。下面是10个例子代码,每个例子都使用了不同的高级结构技术,包括位字段、嵌
    发表于 01-05 06:32

    一个经典的结构和联合体共用的实例

    Linux 中可以 使用 sizeof 进行获取,默认为字节对齐的大小。 联合体 联合体的参数共享同一个内存地址,所占的内存大小完全是由联合体中参数类型决定字长,然后数据共享,内存共享等。 结构和联合体
    发表于 12-16 07:14

    结构声明与定义

    1、声明 结构的声明使用struct关键字,如果我们想要把我们的学籍信息组织一下的话,可以这样表示: struct Info { unsigned long identifier;//学号
    发表于 12-11 07:52

    typedef结构使用

    虽然结构的出现能够让我们有一个更科学的数据结构来管理数据,但是每次使用结构都需要struct
    发表于 12-08 07:04

    为什么不建议用匿名结构

    说起匿名结构,想必大家第一感觉就是看着好高大上的名字,但实际上也就那样。 typedef struct { union { struct { uint8_t bit_0:1
    发表于 12-04 07:39

    modbus消息帧的模块化架构介绍

    01/02/03/04 读取线圈/输入/保持寄存器 数据写入 05/06/15/16 写入单个/多个寄存器 诊断类 08/0B/0E 设备诊断/异常报告 3. 数据字段:操作参数的载体 数据字段
    发表于 11-17 08:15

    网络通讯的结构及地址

    1. 网络地址结构 Socket通过结构描述网络地址,最常用的是IPv4地址结构sockaddr_in(定义在): struct sockaddr_in
    发表于 11-17 07:59

    解码智能电表:OBIS代码的结构、功能与应用全景

    它就像电能表的“身份证号”和“数据字典”,确保了每一条数据都能被精确地识别和理解。
    的头像 发表于 11-13 17:07 1927次阅读
    解码智能电表:OBIS代码的<b class='flag-5'>结构</b>、功能与应用全景

    C语言结构使用

    有时候需要将不同类型的数据组合为一个整体,以便于引用。例如,一名学生有学号、姓名、性别、年龄等属性,如果针对每个属性都单独定义一个变量,那么当有多名学生时变量就难以分清。结构就是用来管理不同类
    发表于 11-12 08:30

    NVMe高速传输之摆脱XDMA设计20: PCIe应答模块设计

    所示。图1TLP写处理模块结构图当axis_cq总线中出现数据流传输时,应答模块首先对传输的TLP报头的类型字段进行解析,如果为存储器写请求则由写处理模块进一步解析。写处理模块提取出TLP报头的地址
    发表于 08-12 16:04

    NVMe高速传输之摆脱XDMA设计14: PCIe应答模块设计

    如图1所示。 图1TLP写处理模块结构图 当axis_cq总线中出现数据流传输时,应答模块首先对传输的TLP报头的类型字段进行解析,如果为存储器写请求则由写处理模块进一步解析。写处理模块提取
    发表于 08-04 16:44

    定义IO初始化结构

    由上述IOPORT相关功能的枚举类型我们可以知道,在对IOPORT模块进行初始化时需要根据情况配置它们。因此我们定义一个IOPORT初始化的结构类型IOPORT_Init_t,它的成员包括了由上述所有枚举类型所声明的变量,因此该结构
    的头像 发表于 07-16 16:26 1692次阅读

    智能AI面临非结构数据难题:IBM推出解决方案

    ,同时提供一个开放的混合数据基础架构和企业级的结构化和非结构数据管理。 智能AI面临非结构
    的头像 发表于 07-02 09:40 743次阅读