c++内存| 内存对齐

github热门推荐 › c++内存| 内存对齐 (第 78 章)
文章工具

内存对齐是 C++ 编译器自动执行的底层内存布局规则,深刻影响程序的内存占用、运行效率、跨平台兼容性,也是 C++ 开发必须掌握的核心知识点。本文将完整讲解内存对齐的定义、原则、原因、优点,结合实例计算结构体对齐后的字节数,并说明 C++ 手动配置内存对齐的方法。


一、什么是内存对齐?

内存对齐是编译器的自动内存排布机制:编译器会将程序中的每个数据单元(基本类型变量、结构体成员等),安排在内存地址为字长整数倍的位置,避免数据随意散落存储。

简单来说:数据在内存中的起始地址,必须是自身大小的整数倍,编译器会自动填充空白字节来满足这个规则。


二、内存对齐的三大核心原则

以结构体(内存对齐最典型场景)为例,遵循 3 条不可违背的原则(对齐基数:编译器默认对齐值,常见为 4/8 字节):

  1. 首地址对齐
    :结构体变量的首地址,能被「最宽基本类型成员大小」和「对齐基数」的较小值整除;
  2. 成员偏移对齐
    :每个成员相对于结构体首地址的偏移量,是「成员自身大小」和「对齐基数」的较小值的整数倍,不满足则编译器自动填充字节;
  3. 总大小对齐
    :结构体总大小,是「最宽基本类型成员大小」和「对齐基数」的较小值的整数倍,末尾不满足则自动填充尾部字节。

三、内存对齐实例:64 位编译器完整测试

以下代码可直接复制运行,清晰展示基础类型大小 + 结构体对齐后的总字节数:

C++ 片段需补全 main() 函数才能运行在实训台打开 →
<span leaf=""><span class="code-snippet__comment">/*</span></span></code><code><span leaf="">说明:程序是在 64 位编译器下测试的</span></code><code><span leaf="">*/</span></code><code><span leaf=""><span class="code-snippet__meta">#include <iostream></span></span></code><code><span leaf=""><span class="code-snippet__keyword">using</span> <span class="code-snippet__keyword">namespace</span> <span class="code-snippet__title">std</span>;</span></code><code><span leaf=""><span class="code-snippet__keyword">struct</span> A</span></code><code><span leaf="">{</span></code><code><span leaf="">    <span class="code-snippet__built_in">short</span> <span class="code-snippet__keyword">var</span>;   <span class="code-snippet__comment">// 2 字节</span></span></code><code><span leaf="">    <span class="code-snippet__built_in">int</span> var1;    <span class="code-snippet__comment">// 填充2字节,2+2+4=8</span></span></code><code><span leaf="">    <span class="code-snippet__built_in">long</span> var2;   <span class="code-snippet__comment">// 8+4=12</span></span></code><code><span leaf="">    <span class="code-snippet__built_in">char</span> var3;   <span class="code-snippet__comment">// 填充3字节,12+1+3=16</span></span></code><code><span leaf="">    <span class="code-snippet__built_in">string</span> s;    <span class="code-snippet__comment">// 16+32=48</span></span></code><code><span leaf="">};</span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__built_in">int</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">main</span></span><span class="code-snippet__function">()</span></span></code><code><span leaf="">{</span></code><code><span leaf="">    <span class="code-snippet__built_in">short</span> <span class="code-snippet__keyword">var</span>;</span></code><code><span leaf="">    <span class="code-snippet__built_in">int</span> var1;</span></code><code><span leaf="">    <span class="code-snippet__built_in">long</span> var2;</span></code><code><span leaf="">    <span class="code-snippet__built_in">char</span> var3;</span></code><code><span leaf="">    <span class="code-snippet__built_in">string</span> s;</span></code><code><span leaf="">    A ex1;</span></code><code><span leaf="">    cout << <span class="code-snippet__keyword">sizeof</span>(<span class="code-snippet__keyword">var</span>) << endl;   <span class="code-snippet__comment">// 2 short</span></span></code><code><span leaf="">    cout << <span class="code-snippet__keyword">sizeof</span>(var1) << endl;  <span class="code-snippet__comment">// 4 int</span></span></code><code><span leaf="">    cout << <span class="code-snippet__keyword">sizeof</span>(var2) << endl;  <span class="code-snippet__comment">// 4 long</span></span></code><code><span leaf="">    cout << <span class="code-snippet__keyword">sizeof</span>(var3) << endl;  <span class="code-snippet__comment">// 1 char</span></span></code><code><span leaf="">    cout << <span class="code-snippet__keyword">sizeof</span>(s) << endl;     <span class="code-snippet__comment">// 32 string</span></span></code><code><span leaf="">    cout << <span class="code-snippet__keyword">sizeof</span>(ex1) << endl;   <span class="code-snippet__comment">// 48 struct</span></span></code><code><span leaf="">    <span class="code-snippet__keyword">return</span> <span class="code-snippet__number">0</span>;</span></code><code><span leaf="">}</span>

对齐计算过程(64 位,默认对齐基数 8)

  1. short var
    :占用 2 字节,无前置填充;
  2. int var1
    :需要偏移量为 4 的倍数,填充 2 字节,总占用到 8 字节;
  3. long var2
    :占用 4 字节,偏移到 12 字节;
  4. char var3
    :占用 1 字节,需要总大小为 4 的倍数,填充 3 字节,偏移到 16 字节;
  5. string s
    :占用 32 字节,最终结构体总大小 = 48 字节。


数组的内存对齐

规则

  1. 数组本身不产生额外对齐填充
    ,数组 = 连续存储的多个同类型元素;
  2. 每个元素按自身类型对齐;
  3. 数组总大小 = 单个元素大小 × 元素个数
    。

示例

char[5]、int[3]、double[2] 大小直接计算,无填充。



结构体内包含数组

规则

  1. 数组作为结构体普通成员,按数组元素类型对齐;
  2. 数组占用空间 = 元素大小 × 个数;
  3. 整体结构体仍遵守总大小对齐规则。


结构体嵌套结构体

规则

  1. 嵌套的子结构体视为一个整体成员;
  2. 嵌套成员的偏移量,按子结构体的对齐单位(子结构体最宽基本类型)对齐;
  3. 最终总大小按整个结构体最宽基本类型对齐。


所有特殊场景测试代码整合在一起,可直接复制运行:

C++ 片段需补全 main() 函数才能运行在实训台打开 →
<span leaf=""><span class="code-snippet__meta">#include <iostream></span></span></code><code><span leaf=""><span class="code-snippet__keyword">using</span> <span class="code-snippet__keyword">namespace</span> <span class="code-snippet__title">std</span>;</span></code><code><span leaf=""><span class="code-snippet__comment">// --------------------------</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 1. 普通数组(无嵌套)</span></span></code><code><span leaf=""><span class="code-snippet__comment">// --------------------------</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__keyword">void</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">testArray</span></span><span class="code-snippet__function">()</span> {</span></code><code><span leaf="">    <span class="code-snippet__built_in">char</span> cArr[<span class="code-snippet__number">5</span>];       <span class="code-snippet__comment">// 1*5=5</span></span></code><code><span leaf="">    <span class="code-snippet__built_in">int</span> iArr[<span class="code-snippet__number">3</span>];        <span class="code-snippet__comment">// 4*3=12</span></span></code><code><span leaf="">    <span class="code-snippet__built_in">double</span> dArr[<span class="code-snippet__number">2</span>];     <span class="code-snippet__comment">// 8*2=16</span></span></code><code><span leaf="">    cout << <span class="code-snippet__string">"char[5]    : "</span> << <span class="code-snippet__keyword">sizeof</span>(cArr) << endl;</span></code><code><span leaf="">    cout << <span class="code-snippet__string">"int[3]     : "</span> << <span class="code-snippet__keyword">sizeof</span>(iArr) << endl;</span></code><code><span leaf="">    cout << <span class="code-snippet__string">"double[2]  : "</span> << <span class="code-snippet__keyword">sizeof</span>(dArr) << endl;</span></code><code><span leaf="">}</span></code><code><span leaf=""><span class="code-snippet__comment">// --------------------------</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 2. 结构体 包含 数组</span></span></code><code><span leaf=""><span class="code-snippet__comment">// --------------------------</span></span></code><code><span leaf=""><span class="code-snippet__keyword">struct</span> StructWithArray {</span></code><code><span leaf="">    <span class="code-snippet__built_in">char</span> a;         <span class="code-snippet__comment">// 1 + 填充3 = 4</span></span></code><code><span leaf="">    <span class="code-snippet__built_in">int</span> b[<span class="code-snippet__number">2</span>];       <span class="code-snippet__comment">// 4*2=8</span></span></code><code><span leaf="">    <span class="code-snippet__built_in">char</span> c[<span class="code-snippet__number">3</span>];      <span class="code-snippet__comment">// 3 + 填充1 = 4</span></span></code><code><span leaf="">};</span></code><code><span leaf=""><span class="code-snippet__comment">// 总大小:4+8+4=16(最宽类型int=4,16是4的倍数)</span></span></code><code><span leaf=""><span class="code-snippet__comment">// --------------------------</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 3. 结构体嵌套结构体</span></span></code><code><span leaf=""><span class="code-snippet__comment">// --------------------------</span></span></code><code><span leaf=""><span class="code-snippet__keyword">struct</span> Inner {</span></code><code><span leaf="">    <span class="code-snippet__built_in">char</span> a;     <span class="code-snippet__comment">// 1 + 填充3 = 4</span></span></code><code><span leaf="">    <span class="code-snippet__built_in">int</span> b;      <span class="code-snippet__comment">// 4</span></span></code><code><span leaf="">};</span></code><code><span leaf=""><span class="code-snippet__comment">// Inner 大小:8</span></span></code><code><span leaf=""><span class="code-snippet__keyword">struct</span> Outer {</span></code><code><span leaf="">    <span class="code-snippet__built_in">int</span> x;          <span class="code-snippet__comment">// 4</span></span></code><code><span leaf="">    Inner <span class="code-snippet__keyword">in</span>;       <span class="code-snippet__comment">// 8</span></span></code><code><span leaf="">    <span class="code-snippet__built_in">char</span> y;         <span class="code-snippet__comment">// 1 + 填充7 = 8</span></span></code><code><span leaf="">};</span></code><code><span leaf=""><span class="code-snippet__comment">// 最宽基本类型 int=4,总大小必须是4的倍数</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 4 + 8 + 8 = 16</span></span></code><code><span leaf=""><span class="code-snippet__comment">// --------------------------</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 4. 混合复杂场景:嵌套 + 数组</span></span></code><code><span leaf=""><span class="code-snippet__comment">// --------------------------</span></span></code><code><span leaf=""><span class="code-snippet__keyword">struct</span> Complex {</span></code><code><span leaf="">    <span class="code-snippet__built_in">char</span> c;            <span class="code-snippet__comment">// 1 + 3填充</span></span></code><code><span leaf="">    <span class="code-snippet__built_in">int</span> arr[<span class="code-snippet__number">2</span>];        <span class="code-snippet__comment">// 8</span></span></code><code><span leaf="">    Inner inn;         <span class="code-snippet__comment">// 8</span></span></code><code><span leaf="">    <span class="code-snippet__built_in">double</span> d;          <span class="code-snippet__comment">// 8</span></span></code><code><span leaf="">};</span></code><code><span leaf=""><span class="code-snippet__comment">// 总大小:4+8+8+8=28 → 补齐到 32(最宽double=8)</span></span></code><code><span leaf=""><span class="code-snippet__comment">// --------------------------</span></span></code><code><span leaf=""><span class="code-snippet__comment">// 主函数测试</span></span></code><code><span leaf=""><span class="code-snippet__comment">// --------------------------</span></span></code><code><span leaf=""><span class="code-snippet__function"><span class="code-snippet__built_in">int</span></span><span class="code-snippet__function"> </span><span class="code-snippet__function"><span class="code-snippet__title">main</span></span><span class="code-snippet__function">()</span> {</span></code><code><span leaf="">    cout << <span class="code-snippet__string">"==== 数组大小 ===="</span> << endl;</span></code><code><span leaf="">    testArray();</span></code><code><span leaf="">    cout << <span class="code-snippet__string">"n==== 结构体含数组 ===="</span> << endl;</span></code><code><span leaf="">    cout << <span class="code-snippet__string">"StructWithArray: "</span> << <span class="code-snippet__keyword">sizeof</span>(StructWithArray) << endl;</span></code><code><span leaf="">    cout << <span class="code-snippet__string">"n==== 嵌套结构体 ===="</span> << endl;</span></code><code><span leaf="">    cout << <span class="code-snippet__string">"Inner: "</span> << <span class="code-snippet__keyword">sizeof</span>(Inner) << endl;</span></code><code><span leaf="">    cout << <span class="code-snippet__string">"Outer: "</span> << <span class="code-snippet__keyword">sizeof</span>(Outer) << endl;</span></code><code><span leaf="">    cout << <span class="code-snippet__string">"n==== 复杂混合结构 ===="</span> << endl;</span></code><code><span leaf="">    cout << <span class="code-snippet__string">"Complex: "</span> << <span class="code-snippet__keyword">sizeof</span>(Complex) << endl;</span></code><code><span leaf="">    <span class="code-snippet__keyword">return</span> <span class="code-snippet__number">0</span>;</span></code><code><span leaf="">}</span>

四、为什么要进行内存对齐?(硬件底层原因)

内存对齐不是语法要求,而是硬件强制约束,核心原因都来自处理器 / 硬件限制:

  1. 部分硬件仅支持存取对齐数据,访问非对齐数据会直接触发程序异常;
  2. 非对齐数据的存取操作,无法保证原子性,多线程场景下会引发数据错乱;
  3. CPU 读取非对齐数据,需要拆分多次内存读取,访问速度大幅降低;
  4. 部分处理器会触发对齐陷阱(alignment trap),导致程序崩溃;
  5. 复杂数据指令不支持非对齐存取,只能通过对齐保证正常运行。


五、内存对齐的优点

  1. 提升跨平台兼容性
    不同硬件平台对内存访问限制不同,内存对齐能屏蔽底层差异,代码无需修改即可在 Windows/Linux/ 嵌入式设备正常运行,避免访问异常。
  2. 提高内存访问效率
    CPU 读取内存是按块读取(而非单个字节),对齐后数据刚好落在一个读取块内,无需多次读取,大幅提升数据访问速度。


六、C++ 如何手动设置内存对齐?

编译器默认内存对齐,但开发中可手动修改对齐规则(缩小 / 取消对齐、指定对齐值),常用两种方式:

1. 编译器指令:设置对齐基数

C++ 片段需补全 main() 函数才能运行在实训台打开 →
<span leaf=""><span class="code-snippet__comment">// 手动设置 4 字节对齐</span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">pragma</span></span><span class="code-snippet__meta"> pack(push, 4)</span></span></code><code><span leaf=""><span class="code-snippet__keyword">struct</span> <span class="code-snippet__title">Test</span> {</span></code><code><span leaf="">    <span class="code-snippet__type">char</span> a;</span></code><code><span leaf="">    <span class="code-snippet__type">int</span> b;</span></code><code><span leaf="">};</span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">pragma</span></span><span class="code-snippet__meta"> pack(pop) </span><span class="code-snippet__meta"><span class="code-snippet__comment">// 恢复默认对齐</span></span></span>

2. C++11 标准关键字:alignas /alignof


C++ 片段需补全 main() 函数才能运行在实训台打开 →
<span leaf=""><span class="code-snippet__comment">// 强制变量按 8 字节对齐</span></span></code><code><span leaf="">alignas(<span class="code-snippet__number">8</span>) <span class="code-snippet__built_in">int</span> num;</span></code><code><span leaf=""><span class="code-snippet__comment">// 查询类型的对齐要求</span></span></code><code><span leaf="">cout << alignof(<span class="code-snippet__built_in">int</span>) << endl;    <span class="code-snippet__comment">// 输出4</span></span></code><code><span leaf="">cout << alignof(Test) << endl;   <span class="code-snippet__comment">// 输出手动设置的对齐值</span></span>

3. 取消内存对齐(紧凑布局)


C++ 片段需补全 main() 函数才能运行在实训台打开 →
<span leaf=""><span class="code-snippet__comment">// GCC/Clang</span></span></code><code><span leaf=""><span class="code-snippet__keyword">struct</span> __attribute__((packed)) NoAlign {</span></code><code><span leaf="">    <span class="code-snippet__built_in">char</span> a;</span></code><code><span leaf="">    <span class="code-snippet__built_in">int</span> b;</span></code><code><span leaf="">};</span></code><code><span leaf=""><span class="code-snippet__comment">// MSVC</span></span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">pragma</span></span><span class="code-snippet__meta"> pack(1)</span></span></code><code><span leaf=""><span class="code-snippet__keyword">struct</span> NoAlign {</span></code><code><span leaf="">    <span class="code-snippet__built_in">char</span> a;</span></code><code><span leaf="">    <span class="code-snippet__built_in">int</span> b;</span></code><code><span leaf="">};</span></code><code><span leaf=""><span class="code-snippet__meta">#</span><span class="code-snippet__meta"><span class="code-snippet__keyword">pragma</span></span><span class="code-snippet__meta"> pack()</span></span>


总结

  1. 内存对齐是编译器自动填充字节,让数据存放在符合硬件要求的内存地址的机制;
  2. 结构体对齐遵循:首地址对齐 → 成员偏移对齐 → 总大小对齐三大原则;
  3. 对齐的核心目的:适配硬件限制、保证程序稳定、提升访问效率;
  4. C++ 支持通过 #pragma pack、alignas 手动配置对齐规则,满足特殊场景需求。


⚠️ 版权声明

本文为免费文章,欢迎转载。转载请注明出处:一木科技(https://www.pingquan.vip/2026/05/31/c%e5%86%85%e5%ad%98-%e5%86%85%e5%ad%98%e5%af%b9%e9%bd%90/),并保留原文链接。