**数据结构对齐**是程式编译后資料在記憶體內的佈局与使用方式。包括三方面内容：**数据对齐**、**数据结构填充**（padding）与**包入**（packing）。

现代计算机CPU一般是以32位元或64位元大小作地址对齐，以32位元架構的計算機舉例,每次以連續的4位元組為一個區間,第一個位元組的位址位在每次CPU抓取資料大小的邊界上,除此之外,如果要访问的变量没有对齐，可能会触发总线错误。

当資料小于计算机的字（word）尺寸，可能把几个資料放在一个字中，称为**包入**（packing）。

许多编程语言自动处理数据结构对齐。Ada语言， PL/I, Pascal, 某些C语言与C++实现, D语言, Rust, 与汇编语言允许特别控制对齐的方式。

定义
--

内存地址*a*被称为*n字节对齐*，*a*是*n*的倍数（*n*应是2的幂），也可以理解為當被访问的数据长度为*n* 字节時，数据地址为*n*字节对齐。如果内存未对齐，称作*misaligned*。

内存指针是对齐的，如果它所指的数据是对齐的。指向聚合数据（aggregate data，如struct或数组）是对齐的，当且仅当它的每个组成数据是对齐的。

体系结构
----

### RISC

大多数RISC处理器在加载或存储指令访问错位的地址时，会产生一个对齐错误。这允许操作系统使用其他指令来模拟错位的访问。例如，对齐错误处理程序可以使用字节加载或存储（其总是对齐的）来模拟更大的加载或存储指令。

一些架构，如MIPS架构有特殊的无对齐加载和存储指令。一条无对齐的加载指令从具有最低字节地址的内存字中获取字节，另一条指令从具有最高字节地址的内存字中获取字节。同样的，store-high和store-low指令分别在较高和较低的内存字中存储相应的字节。

DEC Alpha架构对不对齐的加载和存储采用了两步法。第一步是将上层和下层的内存字加载到独立的寄存器中。第二步是使用类似于MIPS指令的特殊低/高指令来提取或修改内存字。通过将修改后的内存字存储到内存中，就完成了一个无对齐存储。造成这种复杂性的原因是，最初的Alpha架构只能读取或写入32位或64位的值。这被证明是一个严重的限制，经常导致代码臃肿和性能不佳。为了解决这个限制，在最初的架构中加入了一个名为 "字节字扩展"（BXW）的扩展。它包括字节和字的加载和存储指令。

因为这些指令比正常的内存加载和存储指令更大、更慢，所以只有在必要时才可以使用它们。一些C和C++编译器有一个 "无对齐 "属性，可以应用于需要无对齐指令的指针。

### x86

x86体系架构最初是不要求内存对齐。一些SSE2指令要求数据是128比特(16字节)对齐。有些CPU指令用于未对齐访问如MOVDQU。读写内存操作仅在对齐时才是原子的。

C语言struct在x86上的对齐
-----------------

C语言数据结构内的成员按照先后顺序在内存中存储。

### 默认对齐

结构体中每个成员的类型通常有一个默认的对齐方式，也就是说，除非程序员另有要求，否则它将在一个预先确定的边界上对齐。以下典型的对齐方式对微软（Visual C++）、Borland/CodeGear（英语：）（C++Builder）、Digital Mars（英语：）（DMC）和GNU（GCC）的编译器在为32位x86编译时有效。

一个**char**（一个字节）变量将被1字节对齐。

一个**short**（两个字节）变量将是2字节对齐的。

一个**int**（四个字节）变量将是4字节对齐的。

一个**long**（四个字节）变量将被4字节对齐。

一个**float**（四个字节）变量将是4字节对齐的。

一个**double**（8个字节）变量在Windows上是8字节对齐的，在Linux上是4字节对齐的（用-malign-double编译时选项是8字节）。

一个**long long**（8个字节）变量将被4字节对齐。

一个**long double**（C++Builder和DMC为10个字节，Visual C++为8个字节，GCC为12个字节）变量在C++Builder上将是8字节对齐，DMC为2字节对齐，Visual C++为8字节对齐，GCC为4字节对齐。

任何**指针**（四个字节）都将是4字节对齐的。(例如：`char*`, `int*`)

与32位系统相比，LP64 64位系统在对齐方面唯一值得注意的区别是。

一个**long**（八个字节）变量将是8字节对齐的。

一个**double**（8个字节）变量将是8字节对齐的。

一个**long long**（8个字节）变量将是8字节对齐的。

一个**long double**（在Visual C++中是8个字节，在GCC中是16个字节）变量在Visual C++中是8字节对齐的，在GCC中是16字节对齐的。

任何**指针**（八个字节）变量都将是8字节对齐的。

有些数据类型取决于实现方式。

### 指定对齐

一些编译器（Microsoft, Borland, GNU,等等）使用#pragma directive指定对齐的包入（packing）。例如：

```
#pragma pack(push) /\* push current alignment to stack \*/
#pragma pack(1) /\* set alignment to 1 byte boundary \*/

struct MyPackedData
{
 char Data1;
 long Data2;
 char Data3;
};

#pragma pack(pop) /\* restore original alignment from stack \*/

```

这个结构在32位系统的大小为6字节。 

### 缺省packing与#pragma pack

Microsoft编译器的项目缺省packing(编译选项/Zp)与#pragma pack指令。#pragma pack指令仅能减少packing尺寸。

参见
--

* 数组步长
* 类型双关
* offsetof

参考文献
----

1. ↑ . .  [2015-08-30]. （原始内容存档于2015-10-13）.
2. ↑ .  (PDF).  [2015-08-30]. （原始内容存档 (PDF)于2021-12-16）.
3. ↑   (PDF). IBM. July 1966: 55–56  [2017-11-21]. C28-6571-3. （原始内容存档 (PDF)于2019-05-29）.
4. ↑  Niklaus Wirth.  (PDF): 12. July 1973  [2017-11-21]. （原始内容 (PDF)存档于2015-03-15）.
5. ↑ .  [2012-04-13]. （原始内容存档于2012-04-09）.
6. ↑ .  [2016-06-19]. （原始内容存档于2016-05-09）.
7. ↑ .  [2017-11-21]. （原始内容存档于2017-03-28）.
8. ↑ .  [2017-11-21]. （原始内容存档于2017-01-08）.
9. ↑ . MSDN Library. Microsoft. 2007-07-09  [2011-01-11]. （原始内容存档于2012-10-18）.

* Bryant, Randal E.; David, O'Hallaron.  2003. Upper Saddle River, NJ: Pearson Education. 2003  [2017-11-21]. ISBN 0-13-034074-X. （原始内容存档于2007-08-06）.

外部链接
----

* IBM developerWorks article on data alignment （页面存档备份，存于）
* Article on data alignment and performance （页面存档备份，存于）
* MSDN article on data alignment
* Article on data alignment and data portability （页面存档备份，存于）
* Byte Alignment and Ordering （页面存档备份，存于）
* Intel Itanium Architecture Software Developer's Manual （页面存档备份，存于）
* Data Alignment when Migrating to 64-Bit Intel® Architecture （页面存档备份，存于）
* PowerPC Microprocessor Family: The Programming Environments for 32-Bit Microprocessors