简体   繁体   English

我如何将结构的成员复制到C中的double数组中?

[英]How do i copy members of a struct into an array of double in C?

I have a struct of a struct having members like this 我有一个这样的成员的结构

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};

now i want to copy the members of the above instance into the array of double say, for eg., 现在我想将上述实例的成员复制到重复说的数组中,例如,

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

Its too tedious. 太乏味了。 Pls help whats the best way to do this. 请帮助实现此目的的最佳方法。

The best solution is to simply use memcpy. 最好的解决方案是简单地使用memcpy。 You'll need to guard against padding in the struct - there should be none in this case, but it is good practice to always do a compile-time check: 您需要防止在结构中进行填充-在这种情况下应该没有填充,但是最好始终进行编译时检查:

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

Once that's checked, then just merrily memcpy away: 一旦检查完成,就可以轻松地进行以下操作:

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

If you for some reason need to index individual item names, and changing the types is an option, consider using unions: 如果出于某种原因需要索引各个项目名称,并且可以更改类型,请考虑使用联合:

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; 

Now it would be possible to do stuff like: 现在可以执行以下操作:

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

but also to access individual items by name: 还可以通过名称访问单个项目:

featureSetOfPolledData.acc_features.xMin = 1.0;

Lundin provided a good answer 隆丁提供了一个很好的答案

This answer is not a solution. 这个答案不是解决方案。 It's more of a warning of something common that you should not do. 它更多地是警告您不应该执行的常见操作。 It can be tempting do do something like this, but you shouldn't. 做这样的事情可能很诱人,但您不应该这样做。

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

This is likely to work, but does invoke undefined behavior. 这可能有效,但确实会引发未定义的行为。

So why does this cause undefined behavior? 那么,为什么这会导致不确定的行为呢? It's not completely obvious. 这并不完全明显。 The members in the struct is guaranteed to be in the same order as you wrote them. 保证结构中的成员与您编写它们的顺序相同。 Padding can occur in a struct, but for doubles it is extremely unlikely that any compiler would use padding. 填充可以在结构中发生,但是对于double而言,任何编译器都不太可能使用填充。

To be honest, I don't remember the details, but it has to do with that accessing the fields via a pointer this way just simply is undefined behavior in the C standard, and ANY undefined behavior may break your code. 老实说,我不记得详细信息,但是这与通过指针访问字段有关,这只是C标准中的未定义行为,任何未定义行为都可能会破坏您的代码。 Especially if you are enabling optimization. 特别是在启用优化的情况下。

Lundin (same great guy again) wrote this in the comments below: 隆丁(又是一位伟人)在以下评论中写道:

It is UB because the struct layout isn't guaranteed to hold the same alignment as the double (it will in this case, in practice), but also because featureSetOfPolledData is not an array. 之所以是UB,是因为结构布局不能保证与double保持相同的对齐方式(实际上,在这种情况下,它会保持对齐),而且还因为featureSetOfPolledData不是数组。 The part of the standard is the additive operators C17 6.5.6 "For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type." 该标准的一部分是加法运算符C17 6.5.6“出于这些运算符的目的,指向不是数组元素的对象的指针的行为与指向长度为1的数组的第一个元素的指针相同。以对象的类型作为其元素类型。” And then you go beyond your 1 element large array. 然后,您将超越1个元素的大型数组。 The compiler is allowed to assume that you didn't access the data. 允许编译器假定您没有访问数据。

C17 6.3.2.3 gives a special exception that allows you to dissect larger types by using character types. C17 6.3.2.3给出了一个特殊的例外,该例外允许您使用字符类型来剖析较大的类型。 So just for the record, you can actually do like this well-defined by using a character type, increase it with sizeof(double) at each iteration, then convert to double. 因此,仅作记录用途,您实际上可以通过使用字符类型来进行这种定义良好的操作,在每次迭代时将其以sizeof(double)增加,然后转换为double。 Like 喜欢

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

Complete madness, but well-defined 完全疯狂,但定义明确

Assigning structure members to your array individually, as you describe, is the only strictly conforming way to do the job. 正如您所描述的,将结构成员分别分配给您的数组是完成这项工作的唯一严格一致的方法。 Any other alternative requires making assumptions about the layout of the struct members, and C does not make strong enough guarantees about that to support what you want. 任何其他替代方法都需要对struct成员的布局进行假设,并且C不能对此做出足够有力的保证来支持您想要的内容。

However, if you are willing to assume that featureSet_t is laid out without any padding between members, or if you can use an implementation extension to ensure that, and if you want your array to be populated in structure member order, one structure's members after the other's, then you can use memcpy() to do this: 但是,如果您愿意假设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));

That achieves pretty good code simplicity in exchange for non-trivial assumptions about structure layout that nevertheless probably hold in practice. 这样就可以实现相当不错的代码简单性,以换取关于结构布局的一些重要假设,但这些假设在实践中可能仍然适用。 You might, conceivably, get away with just one memcpy() of the overall featureSetOfPolledData object, but IMO, the minimal additional code simplification achieved that way does not justify the stronger assumptions about layout. 可以想象,您可能只需要整个featureSetOfPolledData对象的一个memcpy()就可以了,但是IMO,以这种方式实现的最少的附加代码简化并不能证明对布局的更强假设。

The closest thing that might work as far as sticking to the standard would be to create a union of the struct and the array and to validate that they are the same size: 就遵循标准而言,最有效的方法是创建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

The static_assert verifies that the struct has no internal padding. static_assert验证该结构没有内部填充。 With that, the array members overlay exactly the struct members and they have the same type. 这样,数组成员将完全覆盖struct成员,并且它们具有相同的类型。

With this union, you can freely read from the array and write to the struct or vice versa. 使用此联合,您可以自由地从数组中读取并写入结构,反之亦然。

You can probably create a function taking a combinedFeatureSet_t and returning a double array . 您可能可以创建一个函数,该函数采用combinedFeatureSet_t并返回一个double array It calls another function returning a double array from your featureSet_t for each featureSet_t . 它调用另一个函数,从featureSet_t为每个featureSet_t返回一个double array featureSet_t double array From there, you'll only have to call the first function to get your array . 从那里,您只需要调用第一个函数即可获取array

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM