[英]How do i copy members of a struct into an array of double in 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;
隆丁提供了一个很好的答案
这个答案不是解决方案。 它更多地是警告您不应该执行的常见操作。 做这样的事情可能很诱人,但您不应该这样做。
double *ptr = &featureSetOfPolledData;
for(int i=0; i<53; i++) copy[i] = ptr[i];
这可能有效,但确实会引发未定义的行为。
那么,为什么这会导致不确定的行为呢? 这并不完全明显。 保证结构中的成员与您编写它们的顺序相同。 填充可以在结构中发生,但是对于double而言,任何编译器都不太可能使用填充。
老实说,我不记得详细信息,但是这与通过指针访问字段有关,这只是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 */ }
完全疯狂,但定义明确
正如您所描述的,将结构成员分别分配给您的数组是完成这项工作的唯一严格一致的方法。 任何其他替代方法都需要对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));
这样就可以实现相当不错的代码简单性,以换取关于结构布局的一些重要假设,但这些假设在实践中可能仍然适用。 可以想象,您可能只需要整个featureSetOfPolledData
对象的一个memcpy()
就可以了,但是IMO,以这种方式实现的最少的附加代码简化并不能证明对布局的更强假设。
就遵循标准而言,最有效的方法是创建struct和数组的并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成员,并且它们具有相同的类型。
使用此联合,您可以自由地从数组中读取并写入结构,反之亦然。
您可能可以创建一个函数,该函数采用combinedFeatureSet_t
并返回一个double array
。 它调用另一个函数,从featureSet_t
为每个featureSet_t
返回一个double array
featureSet_t
double array
。 从那里,您只需要调用第一个函数即可获取array
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.