当前位置: 首页 > news >正文

C++ 结构体对齐详解

目录

前言

一、为什么要对结构体进行对齐操作?

二、基本概念

三、 对齐规则

四、示例讲解

1.简单的变量对齐

2.结构体包含有结构体的对齐

结构体成员详细解析

五、使用指令改变对齐方式

__attribute__((packed))

#pragma pack(push, n)

#pragma pack(pop)

六、总结


前言

在C++中,结构体(struct)的对齐是指编译器为确保结构体成员在内存中的地址满足特定的对齐要求而进行的调整。对齐有助于提高访问速度,但同时也可能导致内存空间的浪费。


一、为什么要对结构体进行对齐操作?

结构体对齐的主要目的是优化内存访问速度提高内存利用率

二、基本概念

对齐(Alignment):指数据在内存中按照某种边界方式排列。例如,4字节的整数通常按4字节边界对齐。

填充(Padding):为了满足对齐要求而在数据之间插入的无意义的字节。

边界(Alignment Boundary):存储单元的起始地址必须是其大小的整数倍,例如,4字节的整数应该存储在能被4整除的地址上。

三、 对齐规则

编译器通常遵循以下规则来对齐结构体:

  • 每个成员变量的地址都是其自身大小的整数倍。
  • 结构体的总大小是其最大成员大小的整数倍。
  • 编译器可能会插入填充字节以满足上述对齐要求。

四、示例讲解

1.简单的变量对齐

struct Example {char a;   // 1 byteint b;    // 4 bytesshort c;  // 2 bytes
};

编译器将如何对齐和填充这个结构体?假设默认对齐是4字节:

  • char a 占用1字节,开始地址0x00。
  • int b 需要4字节对齐,下一个可以被4整除的地址是0x04,因此在 a 后面插入3个填充值。
  • short c 需要2字节对齐,b 占用4个字节后,c 可以直接放在下一个地址0x08。

所以结构体在内存中的布局如下:

以结构体在内存中的布局如下:

地址内容
0x00a
0x01填充
0x02填充
0x03填充
0x04b
0x05b
0x06b
0x07b
0x08c
0x09c

总大小是10字节,但为了满足最大成员(int)的对齐要求,编译器可能会将结构体的总大小调整为12字节,使其成为4的倍数。

2.结构体包含有结构体的对齐

编译器将根据每个类型的自然对齐需求来安排各个成员的位置,以便优化内存访问。

#include <iostream>struct InnerStruct {char a;   // 1字节int b;    // 4字节
};struct OuterStruct {char c;             // 1字节InnerStruct inner;  // 包含内部结构体double d;           // 8字节
};

结构体成员详细解析

  1. 内部结构体 InnerStruct

    • char a :占用1字节。
    • int b :通常情况下,占用4字节。
  2. 外部结构体 OuterStruct

    • char c :占用1字节。
    • InnerStruct inner :包含了 InnerStruct 类型的内部结构体。
    • double d :占用8字节。
  • 内部结构体 InnerStruct 的对齐

    • char a 占用1字节。由于 int b 需要4字节对齐,所以 a 后面会有3字节的填充,使得 b 能够对齐到下一个4的倍数地址上。
    • 因此,InnerStruct 的总大小将是8字节(1字节 a + 3字节填充 + 4字节 b)。
  • 外部结构体 OuterStruct 的对齐

    • char c 占用1字节。为了对齐 InnerStructc 后面会有3字节的填充。
    • InnerStruct inner 将从4字节边界开始,总共占用8字节(如上所述)。
    • double d 通常需要8字节对齐,因此在 InnerStruct inner 后面可能会有额外的填充字节。

下面是这两个结构体在默认对齐规则下的内存布局示意图:总结20字节

OuterStruct:
| c (1B) | padding (3B) | InnerStruct (8B) | double d (8B) |InnerStruct:
| a (1B) | padding (3B) | b (4B) |

五、使用指令改变对齐方式

可以使用编译器特定的指令或预处理指令来改变结构体的对齐方式。

__attribute__((packed))

例如,在GCC中,可以使用 __attribute__((packed)) 来消除填充:

struct ExamplePacked {char a;int b;short c;
} __attribute__((packed));

在MSVC中,可以使用 #pragma pack(push, n)#pragma pack(pop)

#pragma pack(push, 1)
struct ExamplePacked {char a;int b;short c;
};
#pragma pack(pop)

#pragma pack(push, n)

  • 功能#pragma pack(push, n) 将当前的对齐设置压入一个栈中,并将对齐值设置为 n
  • 参数
    • n:指定新的对齐值(通常是1、2、4、8或16),表示数据成员应该按照 n 字节边界进行对齐。

#pragma pack(pop)

  • 功能#pragma pack(pop) 用于从栈中弹出之前保存的对齐设置,并恢复该设置。

这样做的结果是结构体成员紧密排列,没有填充字节,但会导致性能下降,因为访问未对齐的数据可能需要更多的处理时间。

六、总结

  • 默认对齐:通常情况下,最好使用编译器的默认对齐方式,以获得最佳性能。
  • 手动对齐:只有在明确知道需要节省内存,并且能接受性能损失的情况下才使用手动对齐。

理解和控制结构体的对齐对于编写高效、可靠的C++程序非常重要。希望这篇详解能够帮助你更好地掌握结构体对齐的概念和应用。

相关文章:

  • 一个易于使用、与Android系统良好整合的多合一游戏模拟器
  • 计算机网络 静态路由及动态路由RIP
  • JSON.parse 解析NaN, Infinity, -Infinity失败
  • 如何通过编程获取桌面分辨率、操作像素点颜色、保存位图和JPG格式图片,以及图片数据的处理和存储方式
  • 锂电池安全监测中会用到哪些气体传感器?
  • Java程序之可爱的小兔兔
  • 【初阶数据结构】深入解析栈:探索底层逻辑
  • 计算机网络面试HTTP篇二
  • 北京互联网企业出海服务小程序开发的主要功能
  • ReactNative进阶(二十八)Metro
  • 对称/非对称加密
  • 解决Microsoft Edge浏览器无法使用英文翻译功能
  • 定个小目标之刷LeetCode热题(28)
  • 孕妈妈如何高效备考PMP,纯经验分享
  • Vue核心指令解析:探索MVVM与数据操作之美
  • 【React系列】如何构建React应用程序
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • 【面试系列】之二:关于js原型
  • 2017-08-04 前端日报
  • create-react-app做的留言板
  • ES6语法详解(一)
  • Java小白进阶笔记(3)-初级面向对象
  • mac修复ab及siege安装
  • MySQL QA
  • Mysql优化
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • tab.js分享及浏览器兼容性问题汇总
  • unity如何实现一个固定宽度的orthagraphic相机
  • Vim Clutch | 面向脚踏板编程……
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 开发基于以太坊智能合约的DApp
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • 优化 Vue 项目编译文件大小
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • #if 1...#endif
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • (175)FPGA门控时钟技术
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (java)关于Thread的挂起和恢复
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (六)vue-router+UI组件库
  • (论文阅读30/100)Convolutional Pose Machines
  • (十一)手动添加用户和文件的特殊权限
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (一)utf8mb4_general_ci 和 utf8mb4_unicode_ci 适用排序和比较规则场景
  • (转)Linux整合apache和tomcat构建Web服务器
  • (转载)Linux 多线程条件变量同步
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • .bat文件调用java类的main方法