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