2
struct Point
{
    double X;
    double Y;
};

Q1)是以下可移植的(编译器/机器)

Point point = { 1.1, 2.2 };
double arr[2] = {};
memcpy(arr, point, sizeof(double)*2);

Q2)结构数组相同

Point *pPoints = new Point[numPoints];
double *pArr = new double[2*numPoints];
memcpy(pArr, pPoints, sizeof(double)*2*numPoints);

在 Windows/MSVC 上,我希望两者都能成功。

编辑:我不是对每个可能的结构/类都问这些问题;我要的是 struct "Point" 的这种特殊情况(注意:只有 2 个 pod,没有虚拟成员/用户构造函数/用户析构函数)。这也可能是一个 C 问题,它与跨编译器的结构对齐和内存布局有关。

到目前为止,我已经知道 c/c++ 标准对 Point 的布局没有强制要求,所以我必须自己使用静态断言来确保它,对吗?

4

4 回答 4

8

您的代码假设sizeof(struct Point) == 2*sizeof(double);. 这是一个危险的假设,因为当您编写和测试代码时它会是正确的,但它是幸运的,而不是定义。运气有一个用完的习惯:)

在这种情况下,您很可能永远不会遇到问题(因为 的定义struct Point不太可能改变,并且机器对齐问题也不太可能在这种类型的可移植性中出现)。话虽如此,这是一个可怕的代码基础模式。

于 2013-07-01T10:37:00.290 回答
0

理论上,结构可以在成员之间和结束后进行填充。所以它不一定与普通双打布局兼容。但是,如果您添加 0 打包和 static_assert 以确保 sizeof(Point) == 2* sizeof(double) 我看不出在实践中失败的方法。

于 2013-07-01T10:38:21.733 回答
0

我想在 mah & quetzacoatl 的答案中添加一些内容——它们既有效又正确。

  1. 以不依赖于未定义事物的方式编写代码。在这里,您的代码可能有效 - 因为 double 是 8 字节对齐的并且通常打包。这仍然是隐含的。您应该通过使用 POD 的大小来确保它始终正常工作。
  2. 如果您需要打包 pod,请通过添加 pragma pack 或类似的东西使其明确。它在代码中声明了您的要求。
  3. 如果代码不符合您的要求,请确保代码失败。如果可能,请使用 static_assert,如果不可能,请使用断言、错误处理代码和/或单元测试。

在您的示例中 - 如果需要打包,请添加 pragma,并确保即使编译器创建的布局与您预期的不同,复制也不会失败。确保编译失败,以防编译器想要创建与所需不同的布局。

于 2013-07-01T12:04:17.247 回答
0

好吧,让我们从我完全支持@mah 所说的事实开始。确实这很糟糕,如果可能的话应该避免。

但是,有时,这是不可能的。例如,您有时需要完全相反:您收到了按特定顺序排列的数字流,并且您希望将其“解包”到结构中以便更好地处理。这就是需要严格控制内存布局的地方。

在这种情况下, if 可以struct Point用适当的打包指令来装饰,这样#pragma pack(1)可能告诉您的编译器不要添加任何 align

请注意,这是#pragma。虽然有些可能看起来有些普遍,但根据定义,它们是特定于编译器/平台的。确保添加一些简单的断言来检查 sizeofs 是否真的相等,以防您更改编译器或将其升级到以不同方式处理 pragma 的版本。

假设您的编译器已经理解了 pack(1) 编译指示(或类似的),您的代码将是安全的,并且这种 POD 结构的 sizeof 确实等于 2*double。在此处查看很好的示例https://stackoverflow.com/a/3318475/717732

我实际上不记得包装在数组中。我几乎可以肯定,数组可以保证以零对齐方式打包。但是,几乎可以肯定。最好检查性病。

于 2013-07-01T10:50:08.283 回答