沿4字节边界对齐

Ton*_*ony 11 c++ cpu internals alignment

我最近考虑了对齐...这是我们通常不必考虑的事情,但我已经意识到某些处理器需要对象沿着4字节边界对齐.这到底意味着什么,以及哪些特定系统具有对齐要求?

假设我有一个任意指针:

unsigned char* ptr

现在,我正在尝试从内存位置检索double值:

double d = **((double*)ptr);

这会导致问题吗?

laa*_*lto 20

它肯定会在某些系统上引起问题.

例如,在基于ARM的系统上,您无法寻址未与4字节边界对齐的32位字.这样做会导致访问冲突异常.在x86上,您可以访问这些非对齐数据,但性能会受到一点影响,因为必须从内存中取出两个单词而不是一个单词.

  • 有些ARM系统甚至可以静默访问低位为零的相应对齐地址,这可能导致很难发现错误. (11认同)

Tam*_*ege 13

以下是英特尔x86/x64参考手册中有关对齐的内容:

4.1.1单词,双字,四字和双四字的对齐

单词,双字和四字不需要在自然边界的内存中对齐.单词,双字和四字的自然边界是偶数地址,地址可被4整除,地址可分别被8整除.但是,为了提高程序的性能,数据结构(尤其是堆栈)应尽可能在自然边界上对齐.原因是处理器需要两次存储器访问才能进行未对齐的存储器访问; 对齐访问只需要一次内存访问.跨越4字节边界的字或双字操作数或跨越8字节边界的四字操作数被认为是未对齐的,并且需要两个单独的存储器总线周期来进行访问.

一些操作双四字的指令要求存储器操作数在自然边界上对齐.如果指定了未对齐的操作数,则这些指令会生成一般保护异常(#GP).双四字的自然边界是可被16整除的任何地址.对双四字运算的其他指令允许未对齐访问(不产生一般保护异常).但是,从存储器访问未对齐的数据需要额外的存储器总线周期.

不要忘了,参考手册是负责开发者和工程师的信息的最终来源,因此,如果您正在处理的事情有据可查,如英特尔CPU,只看了一下参考手册中说,有关的问题.

  • @onebyone:是的,但其他架构也有自己的参考手册. (3认同)
  • 是的,我的意思是有时你想要编写的代码不适用于任何特定的架构(事实上,到目前为止,这恰好是我的常见情况).在那种情况下,CPU参考手册没有帮助,你只能依赖于C++标准. (3认同)

jal*_*alf 5

是的,这可能会导致许多问题。C++ 标准实际上并不能保证它能够工作。您不能在指针类型之间任意转换。

当您将 char 指针转换为双指针时,它使用 a reinterpret_cast,它应用实现定义的映射。您不能保证生成的指针将包含相同的位模式,或者它将指向相同的地址或其他任何内容。从更实际的角度来说,您也不能保证您正在读取的值正确对齐。如果数据被写入一系列字符,那么它们将使用字符的对齐要求。

至于对齐的含义,本质上就是值的起始地址应该能被对齐大小整除。例如,地址 16 在 1、2、4、8 和 16 字节边界上对齐,因此在典型的 CPU 上,这些大小的值可以存储在那里。

地址 6 未在 4 字节边界上对齐,因此我们不应该在那里存储 4 字节值。

值得注意的是,即使在不强制或不需要对齐的 CPU 上,访问未对齐的值通常也会显着减慢速度。