数据结构对齐是代码编译后在记忆体的布局与使用方式。包括三方面内容:数据对齐、数据结构填充(padding)与包入(packing)。
基本介绍
- 中文名:数据结构对齐
- 内容:数据对齐等
- 领域:计算机
简介
现代计算机一般是32比特或64比特地址对齐,如果要访问的变数没有对齐,可能会触发汇流排错误。
当数据小于计算机的字(word)尺寸,可能把几个数据元素放在一个字中,称为包入(packing)。
许多程式语言自动处理数据结构对齐。Ada语言,PL/I,Pascal,某些C语言与C++实现,D语言,Rust,与彙编语言允许特别控制对齐的方式。
定义
记忆体地址a被称为n位元组对齐,当a是n的倍数(n应是2的幂)。
一次记忆体访问被称为对齐的,当被访问的数据长度为n位元组且该数据地址为n位元组对齐。如果记忆体未对齐,称作misaligned。显然,位元组访问总是对齐的。
记忆体指针是对齐的,如果它所指的数据是对齐的。指向聚合数据(aggregate data,如struct或数组)是对齐的,若且唯若它的每个组成数据是对齐的。
x86体系结构
x86体系架构最初是不要求记忆体对齐。一些SSE2指令要求数据是128比特(16位元组)对齐。有些CPU指令用于未对齐访问如MOVDQU。读写记忆体操作仅在对齐时才是原子的。
C语言struct在x86上的对齐
C语言数据结构内的成员先后顺序不能改变。
常见的C语言编译器在32比特x86上,double是8位元组对齐,但Linux上是4位元组对齐(编译选项-malign-double实现8位元组对齐)。
一些编译器(Microsoft,Borland,GNU,等等)使用#pragmadirective指定对齐的包入(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尺寸。
数组步长
数组步长(stride of an array,也称increment, pitch或step size)是程式设计时,相邻数组元素在记忆体中的开始地址的距离,度量单位可以是位元组或者数组元素个数。步长不可小于数组元素的尺寸,但可以大于,表示有填充的位元组。
数组步长如果等于数组元素的尺寸,则数组在记忆体中是连续的。这可称为单位步长(unit stride)。非单位步长适用于二维数组或多维数组。
类型双关
类型双关是计算机科学的术语,指任何编程技术能颠覆或者绕过一门程式设计语言的类型系统,以达成在形式语言内部难以甚至不可能实现的效果。
C语言与C++语言,语法结构如类型转换与union,以及C++增加的reinterpret_cast运算符,用于实现类型双关。
Pascal语言使用records与variants来按照多种方法处理特定数据类型。