在 C++ 中声明、操作和访问未对齐的内存

Declare, manipulate and access unaligned memory in C++

我最近发布了一个关于的问题,但是给出答案,我有点迷茫。我经常听到"aligned memory access is far more efficient than unaligned access",但我其实不确定什么是内存未对齐。因此:

以 32 位计算机读取 4 字节数据为例:

在硬件方面,32 位计算机一次读取 4 个字节,但每 4 个字节读取一次。这是因为内存总线是 4 字节宽。

如果您的 4 字节数据不是从这 4 字节边界之一开始,计算机必须读取内存两次,然后 assemble 将 4 字节写入内部单个寄存器。

根据所选择的体系结构,编译器知道这个和 places/pads 数据结构,因此两个字节数据出现在两个字节边界上,4 字节数据从 4 字节边界开始,等等。这是专门为了避免未对齐的读取。

如果您以字节形式读取数据(例如从串行协议),然后以 32 位字的形式访问它们,则可能会出现未对齐的读取。在速度关键代码中避免这种情况。一般都是给你处理的,不是问题。

是否未对齐取决于数据类型及其大小正如 Gregg 的回答所解释的那样。

一个写得很好的程序通常没有未对齐的内存访问,除非编译器引入它。 (是的,这发生在矢量化过程中,但让我们跳过它)。

但是你可以用C++写程序来强制非对齐内存访问。下面的代码就是这样做的。

#include <iostream>
using namespace std;
int main() {

  int a[3] {1, 2, 3};

  cout << *((long long *)(&a[0])) << endl;
  cout << *((long long *)(&a[1])) << endl;

  cout <<  (long long) (&a[0]) << endl;
  cout << (long long) (&a[1]) << endl;

  return 0;

}

代码的输出是这样的

8589934593
12884901890
70367819479584
70367819479588

这个程序是做什么的? 我声明了一个大小为 3 的整数数组。该数组将按 4 字节对齐,因为 int 是 4 字节数据类型(至少在我的平台上是这样)。所以 a[0] 的地址可以被 4 整除。现在 a[0] 和 a[1] 的地址都可以被 4 整除,但只有其中一个地址可以被 8 整除。

因此,如果我将 a[0] 和 a[1] 的地址转换为指向 long long(在我的平台上是 8 字节数据类型)的指针,然后引用这两个指针,其中一个将是未对齐的内存访问。这不是未定义的行为 AFAIK,但它会比对齐的内存访问慢。

如您所见,此代码包含 C 样式转换,这不是一个好的做法。但我认为强制执行一些奇怪的行为是好的。

如果您对代码的输出有疑问,请告诉我。您应该了解字节序和整数表示以理解前两行。第三行和第四行是整数数组前两个元素的地址。这样应该比较容易理解。