Pod 到 Array 的结构的 memcpy 数组

memcpy array of structs of pods to array

本文关键字:memcpy 数组 结构 Pod Array      更新时间:2023-10-16
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上,我希望两者都能成功。

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

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

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

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

理论上,结构可以在成员之间和结尾后填充。因此,它不一定与普通双打的布局兼容。但是,如果您添加 0 包装和 static_assert 以确保大小(点( == 2* 大小(双倍(,我看不到在实践中失败的方法。

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

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

在这种情况下,if 可能会使用适当的打包指令(如 #pragma pack(1)(装饰struct Point,这可能会告诉您的编译器不要添加任何对齐方式。

请注意,这是 #pragma。虽然有些似乎有些通用,但根据定义,它们是特定于编译器/平台的。请务必添加一些简单的断言来检查 sizeofs 是否真的相等,以防您更改编译器或将其升级到以不同方式处理编译指示的版本。

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

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

我想

在mah和quetzacoatl的答案中添加一些东西 - 既有效又正确。

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

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