【问题标题】:Are doubles on the heap always 8-byte aligned?堆上的双精度数总是 8 字节对齐的吗?
【发布时间】:2014-09-21 05:34:03
【问题描述】:

从阅读各种其他 Stack Overflow 问题来看,double 值似乎有时只能是 4 字节对齐而不是 8(因此存在 GCC 的 -malign-double)。这是否适用于堆和堆栈?

在我看来,如果堆上的 double 值并不总是 8 字节对齐,那么将不可能使用 double* 值执行指针运算,因为递增 double* 会将其推进 8 个字节,但是两个任意的double* 值之间的差异可能不是 8 个字节的倍数。

如果你对我感兴趣的用例感到好奇,我有类似的东西:

#include <iostream>

#include <iostream>
#include <vector>

struct EmptyBase1
{
};

struct EmptyBase2
{
};

struct Point : public EmptyBase1, public EmptyBase2
{
    double x;
    double y;
    double z;
};

int main() {
    std::vector<Point> points(10);
    int stride = &points[1].x - &points[0].x;
    std::cout << stride << std::endl;
    return 0;
}

Visual Studio 在这种情况下没有完全应用空基类优化(参见https://stackoverflow.com/a/12714226/953078),因此不能保证sizeof(Point) == 3 * sizeof(double)stride 是否保证始终在 &amp;points[1].x&amp;points[2].x&amp;points[5].y&amp;points[4].y 等之间提供有效的内存偏移量?

【问题讨论】:

  • 即使它没有在 8 字节边界上对齐,它是否仍然是连续的?连续内存应该保证有效的指针算法。
  • 只有当两个指针都指向同一个数组的元素(或一个超过末尾的元素)时,减去两个指针才是明确定义的。指向数组元素子对象的指针不算数,即使内存是“连续的”。不过,谁知道呢,它可能适用于 VS,这对于您的目的来说可能已经足够了。
  • new T 自然对齐,但您的类型可能未对齐(使用打包指令或reinterpret_cast)。
  • @Brian:我不知道指针减法的限制,这几乎可以直接回答我的问题。这是在某个地方的标准吗?我只提到了 VS,因为它是唯一一个与多个基类有问题的;我确实需要我的代码可以跨多个编译器和平台移植。
  • @IanMackenzie 这是 [expr.add]/6。

标签: c++ alignment


【解决方案1】:

从 3.7.3.1 我们了解分配函数The pointer returned shall be suitably aligned so that it can be converted to a pointer of any complete object type and then used to access the object or array in the storage allocated。所有这一切都表明它必须与硬件适当对齐。因此,您可以设想没有对齐约束的硬件,double 可以与new 进行字节对齐。

您的减法是不合法的,因为这两个双精度数不是doubles 的同一数组/连续块的一部分。但是,将reinterpret_cast 地址指向char* 然后减去那些 指针应该是完全合法的。但是你想解决什么真正的问题?

编辑:正如评论中指出的那样,我现在实际上相当确定即使转换为 char* 并且做减法是非法的。

【讨论】:

  • 我可能确实需要按照您的建议进行 char* 减法 - 我希望避免这种情况。我目前有一个MatrixView 类,用于允许对内存中double 值的任意块进行矩阵运算。它目前被实现为指向第一项、行数、列数和列跨度的指针。列步幅当前存储为整数指针偏移量。我希望能够构造一个有效的MatrixView 指向std::vector&lt;Point&gt; 中的组件数据,但听起来我必须将列步长改为字节。
  • 我不认为转换为char* 会神奇地消除指针运算仅在数组内部有效的要求。典型的例子是 8086,其中一个数组被限制在一个段中,并且指针算法不考虑段边界。
  • 也许 - 但至少在我的情况下,所有双打 都是 在同一个数组中,它恰好是 Point 对象数组而不是双打数组.在这种情况下,您是否可以看到基于 char* 的各种双组件之间的指针算法无效?
猜你喜欢
  • 2011-01-23
  • 1970-01-01
  • 1970-01-01
  • 2019-11-10
  • 1970-01-01
  • 1970-01-01
  • 2016-09-22
  • 2021-05-25
  • 2012-11-16
相关资源
最近更新 更多