如何将结构的成员复制到 C 中的双精度数组中?



>我有一个结构体,具有这样的成员

typedef struct{
double xMin;
double yMin;
double zMin;
double xMax;
double yMax;
double zMax;
double xMedian;
double yMedian;
double zMedian;
double xMean;
double yMean;
double zMean;
double xVar;
double yVar;
double zVar;
double xStD;
double yStD;
double zStD;
}featureSet_t;
typedef struct{
featureSet_t acc_features;
featureSet_t gyr_features;
featureSet_t mag_features;
}combinedFeatureSet_t; 
combinedFeatureSet_t featureSetOfPolledData;
double copy[54] = {0};

现在我想将上述实例的成员复制到双说数组中,例如,

copy[0] =  featureSetOfPolledData.acc_features.xMin;
..
..
copy[53] =  featureSetOfPolledData.mag_features.zstD;

太乏味了。 请帮助什么是最好的方法。

最好的解决方案是简单地使用memcpy。您需要防止在结构中填充 - 在这种情况下应该没有填充,但最好始终执行编译时检查:

_Static_assert(sizeof(featureSetOfPolledData) == sizeof(double[54]), 
"Unexpected padding detected.");

一旦检查完毕,就兴高采烈地离开:

memcpy(copy, &featureSetOfPolledData, sizeof(double[54]));

如果由于某种原因需要为单个项目名称编制索引,并且可以选择更改类型,请考虑使用联合:

typedef union
{
struct
{
double xMin;
double yMin;
double zMin;
double xMax;
double yMax;
double zMax;
double xMedian;
double yMedian;
double zMedian;
double xMean;
double yMean;
double zMean;
double xVar;
double yVar;
double zVar;
double xStD;
double yStD;
double zStD;
};
double array [18];
}featureSet_t;
typedef union
{
struct
{
featureSet_t acc_features;
featureSet_t gyr_features;
featureSet_t mag_features;
};
double array [18*3];  
}combinedFeatureSet_t; 

现在可以做这样的事情了:

for(size_t i=0; i<54; i++)
{
copy[i] = featureSetOfPolledData.array[i];
}

还可以按名称访问单个项目:

featureSetOfPolledData.acc_features.xMin = 1.0;

如您所描述的,将结构成员单独分配给数组是完成这项工作的唯一严格符合的方法。 任何其他替代方法都需要对结构成员的布局做出假设,而 C 对此没有做出足够强大的保证来支持您想要的内容。

但是,如果您愿意假设featureSet_t的布局在成员之间没有任何填充,或者您可以使用实现扩展来确保这一点,并且如果您希望按结构成员顺序填充数组,一个结构的成员在另一个结构的成员之后,那么您可以使用memcpy()来执行此操作:

double copy[54];
memcpy(copy,      &featureSetOfPolledData.acc_features, 18 * sizeof(double));
memcpy(copy + 18, &featureSetOfPolledData.gyr_features, 18 * sizeof(double));
memcpy(copy + 36, &featureSetOfPolledData.mag_features, 18 * sizeof(double));

这实现了相当好的代码简单性,以换取关于结构布局的非平凡假设,但在实践中可能成立。 可以想象,您可能只获得了整个featureSetOfPolledData对象的一个memcpy(),但是IMO,以这种方式实现的最小额外代码简化并不能证明对布局的更强假设是合理的。

就坚持标准而言,最接近的事情是创建结构和数组的union并验证它们的大小是否相同:

static_assert(sizeof(combinedFeatureSet_t) == sizeof(double [54]), "size mismatch");
typedef union {
combinedFeatureSet_t featureset_struct;
double featureset_list[54];
} featureset_u;
featureset_u u;
u.featureset_struct = featureSetOfPolledData;
// read u.featureset_list

static_assert验证结构是否没有内部填充。 这样,数组成员完全覆盖结构成员,并且它们具有相同的类型。

通过这种联合,您可以自由地从数组中读取和写入结构,反之亦然。

Lundin提供了一个很好的答案

这个答案不是解决方案。这更像是对你不应该做的常见事情的警告。做这样的事情可能很诱人,但你不应该。

double *ptr = &featureSetOfPolledData;
for(int i=0; i<53; i++) copy[i] = ptr[i];

这很可能有效,但确实会调用未定义的行为。

那么,为什么这会导致未定义的行为呢?这并不完全明显。保证结构中的成员与您编写它们的顺序相同。填充可以出现在结构中,但对于双精度,任何编译器都不太可能使用填充。

老实说,我不记得细节了,但它与以这种方式通过指针访问字段只是 C 标准中的未定义行为有关,任何未定义的行为都可能破坏您的代码。特别是如果您正在启用优化。

伦丁(又是同一个伟大的家伙)在下面的评论中写道:

它是 UB,因为结构布局不能保证与双精度对齐(在这种情况下,在实践中会如此),但也因为 featureSetOfPolledData 不是一个数组。该标准的一部分是加法运算符 C17 6.5.6"就这些运算符而言,指向不是数组元素的对象的指针的行为与指向长度为 1 的数组的第一个元素的指针相同,对象类型为其元素类型。然后你超越了你的 1 元素大数组。允许编译器假定您未访问数据。

C17 6.3.2.3 提供了一个特殊的例外,允许您使用字符类型剖析较大的类型。因此,仅作为记录,您实际上可以通过使用字符类型来定义良好,在每次迭代时用sizeof(double)增加它,然后转换为double。喜欢

for(uint8_t* ptr = &featureSetOfPolledData; ptr < (uint8_t*)&featureSetOfPolledData + sizeof(double[54]); ptr += sizeof(double)) { double d = *(double*)ptr; /* Put the copying code here */ }

完全疯狂,但定义明确

您可能可以创建一个接受combinedFeatureSet_t并返回double array的函数。它调用另一个函数,为每个featureSet_t从您的featureSet_t返回一个double array。 从那里,您只需调用第一个函数即可获取array

最新更新