【问题标题】:Are float arrays always aligned to 16 byte boundaries?浮点数组是否总是与 16 字节边界对齐?
【发布时间】:2013-11-20 16:27:26
【问题描述】:

我的理解是,如果要对齐,则必须明确指定数组的对齐方式。

但是,我声明的浮点数组似乎总是与 16 字节对齐。

float *ptr1 = new float[1];
cout<<"ptr1: "<<ptr1<<endl;
float *ptr2 = new float[3];
cout<<"ptr2: "<<ptr2<<endl;
float arr1[7];
cout<<"arr1: "<<arr1<<endl;
float arr2[9] __attribute__((aligned(2)));
cout<<"arr2: "<<arr2<<endl;

这是输出

ptr1: 0x13dc010
ptr2: 0x13dc030
arr1: 0x7fff874885c0
arr2: 0x7fff87488590

这是有原因的吗?我正在使用 gcc 4.6.3

但是,如果它是指向浮动位置或静态分配的指针,我看不到它

static float arr3[9] __attribute__((aligned(2)));
cout<<"arr3: "<<arr3<<endl;
float *x;
cout<<"x: "<<x<<endl;

输出:

arr3: 0x4030b2
x: 0x7fff8c7dd9e8

此代码在 x64 上运行。

【问题讨论】:

  • 这取决于你的编译器。查看他们的文档。附言您的 float *x 从未初始化,因此结果基本上是随机的。
  • 我的 gcc 4.8.1 默认只对齐 8 个字节。那是因为malloc 实现会这样做(...operator new 调用)。一言以蔽之:不要指望它。

标签: c++ c memory-management


【解决方案1】:

对齐要求由每个编译器确定,受硬件要求和任何相关ABI 的影响。

C 和 C++ 语言讨论了类型的对齐方式,但它们没有强加任何特定要求(例如,结构的对齐方式至少是其任何成员的对齐方式)。一个有效的实现可以允许所有数据类型字节对齐,或者它可以要求每个标量类型与其自己的大小对齐(后者更常见)。中间对齐是可能的,例如在 4 字节边界上对齐 8 字节类型。

特别是在 x86 上,将标量与其大小对齐可以提高访问效率,但未对齐的访问仍然可以正常工作,尽管速度会慢一些。

float 数组的必需 对齐方式与单个 float 对象的必需对齐方式相同。如果float 是 4 个字节,那么对齐不能大于 4 个字节,因为数组的元素之间没有间隙。

一个特定的编译器可能会选择对数组对象施加更严格的对齐,正如您(可能)看到的那样,如果它可以更有效地访问这些对象。

如果new 运算符是通过调用malloc 来实现的,那么所有new 分配的对象都将具有对任何类型都足够严格的对齐方式。

如果float 数组总是与 16 字节边界对齐,那是因为您的编译器选择以这种方式分配它们,而不是因为语言要求这样做。另一方面,如果您使用别名来强制 float 数组以 4 字节对齐(假设为 sizeof (float) == 4),则对该数组及其元素的访问仍应正常工作。

顺便说一句,当我在我的 x86_64 系统上运行您的代码(在将其包装在 main 程序中之后)时,我得到的结果与您的相似。当我在 x86 系统上运行它时,我得到:

ptr1: 0x9e34008
ptr2: 0x9e34018
arr1: 0xbfefa160
arr2: 0xbfefa17c

我在两个系统上都在 Linux 下使用 gcc。

因此,您的问题的直接答案是否定的,float 数组并不总是与 16 字节边界对齐。

但在大多数情况下,您并没有特别需要关心的理由。除非您使用别名技巧(将某个声明类型的对象视为另一种类型),否则编译器将始终为每个对象至少提供正确访问所需的对齐方式。

【讨论】:

  • 我在我的项目中使用了一些 SSE。所以我想,我应该明确指定对齐到 16 个字节,而不是依赖我的编译器来为我做这件事。我在 x64 上运行它。感谢您的回复。
  • 我自己没用过SSE;我不知道在这种情况下指定所需对齐的正确方法是什么。如果您询问如何使用 SSE 而不是关于对齐的更通用的问题,您可能会获得更多有用的信息。询问您实际尝试解决的问题。谷歌搜索“SSE 对齐”会得到很多结果;我会让你自己看看。
  • 我正在运行代码,只是想确保必须明确指定对齐方式。 SSE 浮点运算需要 16 字节对齐。我的项目中有一个性能关键部分。
  • @Mathai:这可能只是巧合。您需要熟悉 SSE 以及 gcc 与之交互的人或一些实际文档的建议。我回答了你提出的问题;你需要做更多的研究,并可能发布一个新问题,专门关于 SSE 和对齐。
  • 您可能想要关心对齐,例如,在类中声明字段。不正确的顺序会导致对象比需要的大得多。我们说的是大 30%。对于大多数小程序来说这可能无关紧要,但如果你有数百万个这种类型的对象,那么浪费的空间就会增加。另外,复制等一些操作需要更长的时间。如果您制作数百万份副本,这可能会减慢速度。但是你是对的,你不必考虑它来编写它,以便它编译为预期的结果。
【解决方案2】:

我不确定我是否完全理解这个问题,但如果您想要更大的尺寸,我建议使用“double”类型而不是“float”类型。 “Float”通常有 4 个字节(约 7 位)的大小限制,而“double”通常有 8 个字节(约 15 位)的大小限制。

编辑:对不起,我误解了这个问题

【讨论】:

    【解决方案3】:

    这取决于平台最严格的基本类型对齐要求,如 long double,这是我的 Debian 64 系统需要的 16 字节对齐。 堆栈帧对齐也可能受此影响。

    【讨论】:

      猜你喜欢
      • 2012-04-30
      • 1970-01-01
      • 1970-01-01
      • 2019-03-07
      • 2020-03-26
      • 1970-01-01
      • 2016-12-19
      • 2018-01-03
      • 1970-01-01
      相关资源
      最近更新 更多