我有一个这样的成员的结构
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;
太乏味了。 请帮助实现此目的的最佳方法。
答案 0 :(得分:3)
最好的解决方案是简单地使用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;
答案 1 :(得分:1)
伦丁提供了不错的answer
此答案不是解决方案。它更多地是警告您不应该执行的常见操作。做这样的事情可能很诱人,但您不应该这样做。
double *ptr = &featureSetOfPolledData;
for(int i=0; i<53; i++) copy[i] = ptr[i];
这可能有效,但确实会引发未定义的行为。
那么为什么这会导致不确定的行为?这并不完全明显。保证结构中的成员与您编写它们的顺序相同。填充可以在结构中发生,但是对于双精度来说,任何编译器都不太可能使用填充。
说实话,我不记得详细信息,但这与通过指针访问字段的方式有关,这只是C标准中的未定义行为,任何未定义行为都可能破坏您的代码。尤其是在启用优化的情况下。
伦丁(又是一位伟人)在以下评论中写道:
之所以是UB,是因为结构布局不能保证与double保持相同的对齐方式(实际上,在这种情况下,它会保持对齐),而且还因为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 */ }
完全疯狂,但定义明确
答案 2 :(得分:1)
正如您所描述的,将结构成员分别分配给数组是完成这项工作的唯一严格遵循的方法。任何其他替代方法都需要对struct成员的布局进行假设,并且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));
这可以实现相当好的代码简单性,以换取关于结构布局的一些重要假设,而这些假设在实践中可能仍然存在。可以想象,您可能只使用了整个memcpy()
对象中的featureSetOfPolledData
个对象,但是IMO,通过这种方式实现的最少的附加代码简化并不能证明对布局的更强假设。
答案 3 :(得分:1)
在遵循该标准方面,最有效的方法是创建结构和数组的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
验证该结构没有内部填充。这样,数组成员就完全覆盖了struct成员,并且它们具有相同的类型。
通过这种联合,您可以自由地从数组中读取并写入结构,反之亦然。
答案 4 :(得分:0)
您可能可以创建一个使用combinedFeatureSet_t
并返回double array
的函数。它为每个double array
调用另一个从您的featureSet_t
返回featureSet_t
的函数。
从那里,您只需调用第一个函数即可获得array
。