我遇到了这个页面The Lost Art of C Structure Packing,虽然我从来没有必要填写任何结构,但我想学习更多,以便当/如果我也需要 - 我可以 .
它说:
x86或ARM处理器上基本C数据类型的存储通常不会从内存中的任意字节地址开始 . 相反,除char之外的每种类型都有对齐要求;字符可以从任何字节地址开始,但是2字节短路必须从偶数地址开始,4字节整数或浮点数必须从可被4整除的地址开始,8字节长或双精度必须从可被8整除的地址开始签名或未签名没有区别 .
这是否意味着所有32位处理器(x86,ARM,AVR32,PIC32 ......)都具有这种对齐要求?那么16位处理器呢?
如果没有,并且它是特定于设备的,我在哪里可以找到这些信息?我尝试搜索Microchip XC16 Manual,但我找不到对齐要求,说明ints从可被4整除的地址开始 .
我假设信息存在,我不是在寻找正确的关键词 - 如果我在网上搜索更多信息,那么“对齐要求”是什么?
2 回答
这里有两个全球答案 . 是的,所有处理器都有某种对齐惩罚(ARM,MIPS,x86等) . 不,你不能按类型确定 . 所有ARM都没有相同的对齐惩罚,尽管人们认为他们知道旧的ARMv4和ARMv5,你可以以可预测的方式进行未对齐的访问,这种可预测的方式不是我们大多数人所希望的,而你必须启用它 . MIPS和ARM以及其他人可能会对未对齐的传输进行严厉处罚,您将遇到数据错误 . 但由于程序员编程等的性质,至少ARM的默认设置是在某些/更新的内核上禁用该功能 . 您可以根据需要禁用它或启用它 .
所有处理器都会因未对齐传输而受到损失,性能下降,并且这些命中发生在各个层,有时在核心,核心边缘,每个缓存层以及ram的外层 . 由于设计变化如此广泛,您无法提出单一规则 .
同样,由于编译器中的对齐是实现定义的,因此您无法编写可移植代码 . 因此,如果您正在处理处理器(可能是ARM,因为那是大多数人被咬过的地方),启用了未对齐的错误,最便携的解决方案,但不是万无一失的,是用64位变量启动结构,然后是32那么16然后是8.编译器倾向于按照你定义它们的顺序放置东西,只要整个结构在该目标的右边界上开始,那么变量将正确地对齐,不需要填充 . 除了不使用结构,或禁用对齐检查并遭受前端性能命中之外,没有全局解决方案 .
请注意,我们今天通常处理的32位臂使用的是64位AMBA / AXI总线而不是32位,如果启用,它们仍然可以检查传输的所有对齐(16,32,64),但未对齐的性能至少在除非你越过64位对齐边界,否则AMBA / AXI级别不会打你 . 您可能仍会有额外的缓存行命中,但如果您没有AMBA / AXI命中,则不太可能 .
对齐要求有两个注意事项:必需,首选
必需:示例:某些平台需要各种类型,例如
int
要对齐 . 尝试访问未对齐边界上的int
的扭曲代码会导致错误 . 编译器通常会自动对齐数据以防止出现此问题 .效率:可以允许未对齐访问但导致代码更慢 . 许多编译器,而不是打包数据,将默认为对齐数据以提高速度效率 . 通常,此类编译器允许编译器特定的关键字或编译器选项来打包数据,以提高空间效率 .
这些问题适用于各种尺寸的不同处理器 . 8位处理器可能具有16位数据总线,并且需要对齐16位类型 . 用于64位处理器的兼容C编译器可能只有64位类型,甚至
char
. 可能性很大 .C在
<stddef.h>
中提供整数类型max_align_t
. 这可以以各种方式用于确定最小的一般对准要求 .C也有
_Alignas()
对变量进行更严格的对齐 .