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

Posted

技术标签:

【中文标题】在 C++ 中声明、操作和访问未对齐的内存 [关闭]【英文标题】:Declare, manipulate and access unaligned memory in C++ [closed] 【发布时间】:2016-10-07 17:00:05 【问题描述】:

我最近发布了一个关于unaligned memory access 的问题,但给出答案,我有点迷茫。我经常听到“对齐的内存访问比未对齐的访问效率更高”,但我实际上并不确定什么是未对齐的内存。因此:

什么是未对齐内存? 如何在 C++ 中声明未对齐的内容? (小示例程序) 如何访问和操作 C++ 中未对齐的内容? (小示例程序) 是否有一种方法可以使用已定义的行为方法或所有这些方法在 C++ 中操作与平台相关/未定义的行为的未对齐内存?

【问题讨论】:

从您链接到的答案:“在 C++ 中,不可能编写执行未对齐访问而不导致未定义行为的代码”。 【参考方案1】:

某些东西是否未对齐取决于数据类型及其大小,正如 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 样式转换,这不是一个好习惯。但我认为执行一些奇怪的行为很好。

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

【讨论】:

事实证明,打破严格别名是 C++ 中未定义的行为。那部分我不知道。【参考方案2】:

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

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

如果您的 4 字节数据不在这 4 字节边界之一开始,则计算机必须读取内存两次,然后在内部将 4 字节组装到单个寄存器。

根据选择的架构,编译器知道这一点并放置/填充数据结构,以便两个字节数据出现在两个字节边界上,4 字节数据从 4 个字节边界开始,等等。这是为了避免未对齐的读取.

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

【讨论】:

以上是关于在 C++ 中声明、操作和访问未对齐的内存 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

C++ 类内存模型和对齐

c ++垂直声明对齐[关闭]

内存对齐问题

字节对齐

如何捕获未对齐的内存访问?

C++ 结构体对齐