详解c++中的sturct

在c中struct只能存放数据,在c++中为其扩展了创建成员函数的功能,struct中的成员默认都是public的,struct的继承默认也是public,并且它是无法用于定义模板参数 ,这是它与class的主要区别。

虽然在c++中struct可以定义成员函数,不过我们还是将它主要用于定义一些 POD(plain old data),在 C++11 及之后的标准中,POD 类型需要同时满足两个独立条件:

  1. 平凡:类型具有默认的构造/拷贝/移动/析构函数(可自动生成且非虚)
  2. 标准布局(Standard Layout)​​ :内存布局与 C 兼容,成员排列顺序符合特定规则
    同时满足平凡性和标准布局的类型称为 POD 类型,这类数据可以安全使用 memcpy 等底层内存操作,因为它们的内存布局与 C 完全兼容且没有特殊处理需求。

内存对齐

内存对齐主要有三点原因,一是为了提高cpu的访问效率,cpu在读取时是按照块进行读取的,比如64位系统一般一次性读取8字节。二是早期某些平台不对齐访问会直接崩溃 或触发异常,三是为了保证原子操作,原子指令通常要求数据对齐,否则无法保证原子性。

内存对齐的基本规则:

  1. 每个成员 按照其自身大小对齐(char按1字节,int按4字节,double按8字节)
  2. 成员的起始地址必须是其对齐值的整数倍
  3. struct整体大小必须是最大对齐值的整数倍

举例:

cpp 复制代码
struct Example1 {
    char a;     // 偏移0,占用1字节
                // 填充7字节(让double从8的倍数开始)
    double b;   // 偏移8,占用8字节
    char c;     // 偏移16,占用1字节
                // 填充7字节(使总大小为8的倍数)
};  // 总大小:24字节

struct Example2 {
    double b;   // 偏移0,占用8字节
    char a;     // 偏移8,占用1字节
    char c;     // 偏移9,占用1字节
                // 填充2字节(偏移10-11)← int 需要4字节对齐
    int d;      // 偏移12,占用4字节  ← 10不是4的倍数,要从12开始
};  // 总大小:16字节 ✓

struct Example3 {    // 从大到小排列
    double b;   // 偏移0,占用8字节
    int d;      // 偏移8,占用4字节
    char a;     // 偏移12,占用1字节
    char c;     // 偏移13,占用1字节
                // 填充2字节(偏移14-15),使总大小为8的倍数
};  // 总大小:16字节

在内存对齐的情况下,我们想要访问一个数据cpu都只需要读取一次内存,假设没有内存对齐,拿Example1的成员顺序举例,内存的前8字节会存放一个完整的char a(1字节)和double b的前7字节。如果我们想要访问这个double b,cpu就需要访问两次内存才能拼凑出完整的数据。

为了提高运行效率和确保稳健性一般建议开启内存对齐,小建议:

  • 从大到小 的顺序声明成员,可以减少内存浪费(参考Example3)
    在一些嵌入式设备中,内存是比较宝贵的,内存对齐虽然可以提高运行效率,但会浪费一些内存空间,这时候我们可以通过#pragma pack来关闭内存对齐,用时间换空间。
cpp 复制代码
// 正常对齐(默认)
struct Normal {
    char a;     // 1字节
                // 填充7字节
    double b;   // 8字节
    char c;     // 1字节
                // 填充7字节
};  // 总大小:24字节

// 1字节对齐,取消填充
#pragma pack(1)
struct Packed1 {
    char a;     // 1字节
    double b;   // 8字节
    char c;     // 1字节
};  // 总大小:10字节
#pragma pack()  // 恢复默认对齐

// 2字节对齐
#pragma pack(2)
struct Packed2 {
    char a;     // 1字节
                // 填充1字节
    double b;   // 8字节(按2字节对齐,每次最多填充1字节)
    char c;     // 1字节
                // 填充1字节
};  // 总大小:12字节
#pragma pack()

// 4字节对齐
#pragma pack(4)
struct Packed4 {
    char a;     // 1字节
                // 填充3字节
    double b;   // 8字节(按4字节对齐)
    char c;     // 1字节
                // 填充3字节
};  // 总大小:16字节
#pragma pack() //恢复正常对齐

int main() {
    printf("Normal:  %zu 字节\n", sizeof(Normal));
    printf("Pack(1): %zu 字节\n", sizeof(Packed1));
    printf("Pack(2): %zu 字节\n", sizeof(Packed2));
    printf("Pack(4): %zu 字节\n", sizeof(Packed4));
    return 0;
}

//输出
Normal:  24 字节
Pack(1): 10 字节
Pack(2): 12 字节
Pack(4): 16 字节
相关推荐
Lhan.zzZ5 小时前
笔记_2026.4.28_004
c++·ide·笔记·qt
MATLAB代码顾问5 小时前
5大智能算法优化标准测试函数对比(Python实现)
开发语言·python
wuminyu7 小时前
专家视角看Java字节码加载与存储指令机制
java·linux·c语言·jvm·c++
万粉变现经纪人7 小时前
如何解决 pip install llama-cpp-python 报错 未安装 CMake/Ninja 或 CPU 不支持 AVX 问题
开发语言·python·开源·aigc·pip·ai写作·llama
清风明月一壶酒7 小时前
OpenClaw自动处理Word文档全流程
开发语言·c#·word
其实防守也摸鱼7 小时前
CTF密码学综合教学指南--第五章
开发语言·网络·笔记·python·安全·网络安全·密码学
木喃的井盖7 小时前
无锁队列细节
c++·工程
王老师青少年编程7 小时前
csp信奥赛C++高频考点专项训练之字符串 --【字符串基础】:输出亲朋字符串
c++·字符串·csp·高频考点·信奥赛·专项训练·输出亲朋字符串
WBluuue8 小时前
数据结构与算法:莫队(一):普通莫队与带修莫队
c++·算法
小郑加油8 小时前
python学习Day12:pandas安装与实际运用
开发语言·python·学习