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

【C/C++】详解内存对齐问题,C语言内存对齐整理


🔥个人主页:艾莉丝努力练剑

❄专栏传送门:《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、C/C++干货分享&学习过程记录

🍉学习方向:C/C++方向

⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平


前言:本专栏记录了博主C++从初阶到高阶完整的学习历程,会发布一些博主学习的感悟、碰到的问题、重要的知识点,和大家一起探索C++这门程序语言的奥秘。这个专栏将记录博主C++语法、高阶数据结构、STL的学习过程,正所谓“万丈高楼平地起”嘛,我们话不多说,继续进行C++阶段的学习。本文我们不讲C++主线的内容,我们来拓展一下或者说整理一下我们学习时C/C++时经常会提到的一些专有名词,例如形参、实参,显式类型转换和隐式类型转换类型转换,内置类型、内存对齐问题等等。


 C++的两个参考文档:

老朋友(非官方文档):cplusplus

官方文档(同步更新):cppreference



目录

正文

1、什么是内存对齐

2、为什么需要内存对齐

2.1  硬件要求

2.2  性能优化

2.3  跨平台兼容

3、对齐规则详解

3.1  基本数据类型的自然对齐

3.2  结构体的对齐规则

3.3  联合体(union)的对齐

4、结构体成员排列优化

5、内存布局示例

5.1  示例1:基本结构体

5.2  示例2:调整成员顺序优化空间

6、控制对齐方式

6.1  编译器指令

6.2  C++11后的标准方式

6.3  跨平台写法

7、实际开发中的注意事项

8、实际应用场景

8.1  网络协议处理

8.2  硬件寄存器映射

8.3  性能优化

9、检测对齐的方法

10、常见问题与解决方案

10.1  问题1:非对齐访问导致崩溃(ARM平台)

10.2  问题2:结构体大小意外过大

10.3  问题3:跨平台数据不一致

10.4  问题4:跨平台结构体大小不一致

11、调试与检测

11.1  查看对齐值

11.2  检查指针是否对齐

11.3  静态断言(C11)

12、性能影响实测示例

13、高级话题:缓存行对齐

结尾


正文

博主之前就介绍过内存对齐的内容,是在C语言的自定义类型:结构体里面介绍的——

【自定义类型:结构体】:类型声明、结构体变量的创建与初始化、内存对齐、传参、位段

1、什么是内存对齐

内存对齐(Memory Alignment)是指数据在内存中的存储地址必须是某个值的整数倍(通常是2、4、8等2的幂次方)。现代计算机体系结构对内存访问进行了优化,要求特定类型的数据必须从特定倍数的地址开始存储。

2、为什么需要内存对齐

2.1  硬件要求

  • CPU访问效率:多数CPU访问对齐的数据只需要一个总线周期,而非对齐访问可能需要多个周期

  • 硬件支持:某些架构(如ARM)完全不允许非对齐访问,会导致硬件异常

硬件要求多数CPU访问对齐数据效率更高,有些架构(如ARM)直接不支持非对齐访问)

2.2  性能优化

  • 缓存行优化:对齐数据能更好地利用CPU缓存

性能优化对齐数据能更好利用CPU缓存行)

  • SIMD指令:许多SIMD指令要求数据必须对齐

(指令集要求:如SSE/AVX等SIMD指令要求数据必须对齐

2.3  跨平台兼容

  • 不同平台可能有不同的对齐要求

3、对齐规则详解

3.1  基本数据类型的自然对齐

  • char:1字节对齐

  • short:2字节对齐

  • int/float:4字节对齐

  • double/long long:8字节对齐(32位系统可能4字节)

  • 指针:4字节(32位)或8字节(64位)对齐

3.2  结构体的对齐规则

  1. 结构体的对齐要求是其成员中最大对齐要求的那个值

  2. 结构体的大小必须是其对齐要求的整数倍

  3. 每个成员的偏移量必须是其自身对齐值的整数倍

struct Example1 
{char a;      // 1字节int b;       // 4字节(需要从4的倍数地址开始)short c;     // 2字节
};
// 大小可能是12字节(1 + 3填充 + 4 + 2 + 2填充)

3.3  联合体(union)的对齐

  • 对齐要求等于其最大成员的对齐要求

  • 大小等于最大成员的大小(向上对齐)

4、结构体成员排列优化

通过合理排列成员顺序可以节省内存:

// 优化前(12字节)
struct bad_layout 
{char a;int b;short c;
};// 优化后(8字节)
struct good_layout 
{int b;char a;short c;
};

优化原则:

  1. 按对齐值从大到小排列成员

  2. 相同类型的成员尽量集中放置

5、内存布局示例

5.1  示例1:基本结构体

struct S1 
{char a;     // 偏移0// 3字节填充int b;      // 偏移4short c;    // 偏移8// 2字节填充(使总大小为12,是4的倍数)
};
// sizeof(S1) == 12

5.2  示例2:调整成员顺序优化空间

struct S2 
{int b;      // 偏移0char a;     // 偏移4short c;    // 偏移6// 无填充(总大小8,已是4的倍数)
};
// sizeof(S2) == 8

6、控制对齐方式

6.1  编译器指令

  • GCC/Clang:__attribute__((aligned(n))) 或 __attribute__((packed))

// 强制4字节对齐
struct __attribute__((aligned(4))) aligned_struct 
{char a;int b;
};// 取消对齐(packed)
struct __attribute__((packed)) packed_struct 
{char a;int b;
};
  • MSVC: __declspec(align(n))

__declspec(align(16)) struct aligned_struct 
{char a;int b;
};

演示如下:

// 强制16字节对齐
struct alignas(16) AlignedStruct 
{int a;double b;
};// 取消对齐(可能降低性能但节省空间)
#pragma pack(push, 1)
struct PackedStruct 
{char a;int b;short c;
};
#pragma pack(pop)

6.2  C++11后的标准方式

alignas(16) int aligned_array[4];  // 16字节对齐struct alignas(8) MyStruct 
{char a;int b;
};

6.3  跨平台写法

#if defined(_MSC_VER)
#define ALIGN(n) __declspec(align(n))
#else
#define ALIGN(n) __attribute__((aligned(n)))
#endifALIGN(8) struct cross_platform_struct 
{int a;char b;
};

7、实际开发中的注意事项

  1. 网络传输:传输结构体前应序列化或使用#pragma pack(1)。

  2. 文件IO:直接读写结构体要考虑对齐差异。

  3. 跨平台开发:不同平台对齐要求可能不同。

  4. 性能敏感代码:合理安排结构体成员顺序。

  5. SIMD编程:必须保证数据对齐。

8、实际应用场景

8.1  网络协议处理

#pragma pack(push, 1)  // 1字节对齐
struct network_packet 
{uint16_t header;uint32_t length;char data[256];
};
#pragma pack(pop)  // 恢复默认对齐

8.2  硬件寄存器映射

struct hw_register 
{volatile uint32_t CTRL   ALIGN(4);volatile uint32_t STATUS ALIGN(4);volatile uint32_t DATA   ALIGN(4);
};

8.3  性能优化

// 缓存行对齐(通常64字节)
struct cache_line_aligned 
{int data ALIGN(64);
};

9、检测对齐的方法

// C++11
static_assert(alignof(int) == 4, "int must be 4-byte aligned");// 运行时检查
bool is_aligned(const void* p, size_t alignment) 
{return (reinterpret_cast<uintptr_t>(p) % alignment) == 0;
}

10、常见问题与解决方案

10.1  问题1:非对齐访问导致崩溃(ARM平台)

char buffer[100];
int *p = (int *)(buffer + 1);  // 非对齐指针
*p = 42;  // 在ARM上可能崩溃

解决方案:确保指针类型转换后的对齐要求。

// 方法1:使用memcpy
int value = 42;
memcpy(buffer + 1, &value, sizeof(value));// 方法2:确保对齐
int *p = (int *)(buffer + (4 - ((uintptr_t)buffer % 4)));

10.2  问题2:结构体大小意外过大

解决方案:重新排列成员顺序,把大对齐成员放前面。

10.3  问题3:跨平台数据不一致

解决方案:使用序列化代替直接内存拷贝。

10.4  问题4:跨平台结构体大小不一致

解决方案

  1. 使用编译器指令统一对齐方式

  2. 避免直接读写结构体二进制,改用序列化

11、调试与检测

11.1  查看对齐值

#include <stddef.h>
printf("int alignment: %zu\n", _Alignof(int));

11.2  检查指针是否对齐

int is_aligned(const void *ptr, size_t alignment) 
{return ((uintptr_t)ptr % alignment) == 0;
}

11.3  静态断言(C11)

_Static_assert(_Alignof(double) == 8, "double must be 8-byte aligned");

12、性能影响实测示例

示例一:

// 测试对齐访问的性能差异
void test_aligned_access() 
{const int SIZE = 1000000;// 非对齐内存char* unaligned = new char[SIZE * 4 + 1];int* data1 = reinterpret_cast<int*>(unaligned + 1);  // 强制非对齐// 对齐内存int* data2 = new int[SIZE];// 性能测试...
}

示例二:

#include <stdio.h>
#include <time.h>#define SIZE 10000000void test_aligned() 
{_Alignas(16) int array[SIZE];// 测试对齐访问性能...
}void test_unaligned() 
{char buffer[SIZE * 4 + 1];int *array = (int *)(buffer + 1);  // 故意不对齐// 测试非对齐访问性能...
}int main() 
{// 对比两个函数的执行时间
}

13、高级话题:缓存行对齐

对于多线程编程,避免false sharing(伪共享):

struct alignas(64) CacheLineAligned 
{  // 典型缓存行大小64字节int data;// 填充剩余空间
};

结尾

往期回顾:

【C/C++】具有C风格的强制类型转换:显式类型转换、隐式类型转换,C语言强制类型转换

【C/C++】C++引用和指针的对比

【C/C++】形参、实参相关内容整理

【C/C++】Dev-C++的安装与使用以及快捷键整理

【日常问题解决方案】VS2022不小心解决方案资源管理器把关掉了怎么办

VS2022进行监视功能的步骤

结语:本文内容到这里就全部结束了。本文我们介绍了C语言以及C++的内存对齐问题。

http://www.dtcms.com/a/323607.html

相关文章:

  • vulhub-Beelzebub靶机
  • 计算网络相关知识
  • 第15届蓝桥杯Scratch图形化省赛初级组2024年8月24日真题
  • 模型微调与RAG在问答系统中的对比分析
  • [激光原理与应用-205]:光学器件 - LD与DFB的比较
  • leetcode 11. 盛最多水的容器 -java
  • Kubernetes CronJob bug解决
  • B站小波变换视频笔记
  • 原创邮件合并Python工具使用说明(附源码)
  • python---变量作用域
  • 零拷贝技术:提升传统I/O的性能
  • 【C++】string 的特性和使用
  • 欢迎走进《励曼旋耕》
  • LintCode第547题-两数组的交集
  • leetcode 49. 字母异位词分组 - java
  • [激光原理与应用-202]:光学器件 - 增益晶体 - Nd:YVO₄增益晶体的制造过程与使用过程
  • vite面试题及详细答案120题(61-90)
  • 简单聊聊PowerShell
  • Effective C++ 条款32:确定你的public继承塑模出 is-a 关系
  • 【读代码】深度解析 SmolAgents Open Deep Research
  • 杰理-AW-断言-log
  • 计算机网络基础(三)
  • [Shell编程] Shell 函数
  • PyQt5技术栈简述
  • .htaccess 文件上传漏洞绕过总结
  • Linux文件操作详解:一切皆文件
  • 编辑距离-二维动态规划
  • SkyWalking-3--Java Agent开发和集成示例
  • AI智能编程工具汇总
  • ComfyUI版本更新---解决ComfyUI的节点不兼容问题