为什么大小小于 CPU 字大小的数据需要以其大小的倍数对齐?

use*_*750 1 c memory cpu-architecture memory-alignment

我们假设有一个 32 位 CPU 和 2 字节short。我知道 4 字节int需要在 4 的倍数地址处对齐,以避免额外读取。

问题:

  1. 如果 处存储了短路,CPU 仍可以在一次操作中0x1读取。0x0那么,为什么 Shorts 需要以 2 的倍数地址对齐呢?
  2. 如果一个short存储在0x2,为什么它会被认为是对齐和高效的,因为CPU只能从0x0读取并丢弃前两个字节?

有一个问题与此非常相似,但是,答案仅告诉我们short结构体和独立变量中的对齐要求是相同的。还有一条获得 2 票赞成的评论说:

在许多机器上,当数量是 N 字节对齐时,访问 N 字节数量(至少是 {1, 2, 4, 8, 16} 中的 N)的效率最高。生活就是这样;习惯它,因为我怀疑芯片制造商会仅仅因为你认为它不应该是这样而改变它。

但为什么?

sup*_*cat 5

大多数机器都设计有使用“字”地址和字节选择线的组合来寻址的存储器,“字”地址标识一组两个或多个字节,字节选择线指示正在访问字中的哪些字节。当执行一个字或更小的操作时,可以同时访问一个字内的所有字节。大于字大小的操作总是需要拆分为多个操作,并且大多数 CPU 不会关心任何大于字大小的块的对齐;某些 CPU 可能能够将需要访问两个连续字的部分的字大小或更小的操作拆分为更小的操作,但这种能力并不通用。

该标准保证,对于任何 2 的 N 次幂,针对 N 字节对象适当对齐的分配中的 N 倍数偏移量将产生针对 N 字节对象适当对齐的地址。它不能保证字长较小的平台能够容忍较宽松的对齐,因为:

  1. 该标准有意放弃对非便携式结构的管辖权。

  2. 想要提供更强保证的实现是可以自由实现的,想要维护 C 精神的编译器编写者将在没有任何理由不这样做的情况下这样做。

  3. 即使在 8 位平台上,要求字对齐也可能有优势,尽管具有讽刺意味的是,我不知道在 8 位平台上有任何实现这样做过,而在这种情况下,字对齐是最有用的。例如,在 Z80 上,将地址位于 HL 中的 16 位值加载到 DE 的常用方法是:

     mov e,(HL)
     inc hl
     mov d,(hl)
    
    Run Code Online (Sandbox Code Playgroud)

但如果已知 HL 是偶数,则第二条指令可以替换为inc l,这会快两个周期,将总时间从 20 个周期减少到 18 个周期。这并不是一个巨大的性能提升,但如果应用程序永远不会使用奇数地址为字大小的值,它将代表“容易实现的目标”。

  • @0___________:您是否更喜欢 AVR,这是一种 8 位 RISC 微控制器,旨在成为 C 编译器的不错的编译器目标,因为它是在 8080 / Z80 之后多年设计的?但这不能作为示例,因为 AVR 允许“Z”和“Z+1”寻址模式,不需要单独的增量:https://godbolt.org/z/4aa5WE8cP (2认同)