简体   繁体   English

这是工会的正确用法吗

[英]Is this a proper usage of union

I want to have named fields rather than indexed fields, but for some usage I have to iterate on the fields. 我想要命名字段而不是索引字段,但是对于某些用法,我必须在这些字段上进行迭代。 Dumb simplified example: 哑巴简化示例:

struct named_states {float speed; float position;};

#define NSTATES (sizeof(struct named_states)/sizeof(float))
union named_or_indexed_states {
   struct named_states named;
   float indexed[NSTATES];
}
...
union named_or_indexed_states states,derivatives;
states.named.speed = 0;
states.named.position = 0;
...
derivatives.named.speed = acceleration;
derivatives.named.position= states.named.speed;
...
/* This code is in a generic library (consider nstates=NSTATES) */
for(i=0;i<nstates;i++)
    states.indexed[i] += time_step*derivatives.indexed[i];

This avoid a copy from named struct to indexed array and vice-versa, and replace it with a generic solution and is thus easier to maintain (I have very few places to change when I augment the state vector).It also work well with various compiler I tested (several versions of gcc/g++ and MSVC). 这样可以避免从命名结构复制到索引数组,反之亦然,并用通用解决方案替换它,因此更易于维护(当增加状态向量时,我几乎没有地方要更改),并且在各种情况下也能很好地工作我测试过的编译器(gcc / g ++和MSVC的多个版本)。

But theorically, as I understand it, it does not strictly adhere to proper union usage since I wrote named field then read indexed field, and I'm not sure at all we can say that they share same struct fields... 但是从理论上讲,据我了解,它并不严格遵循正确的并集用法,因为我编写了命名字段然后读取了索引字段,而且我不确定我们是否可以说它们共享相同的结构字段...

Can you confirm that's it's theorically bad (non portable)? 您可以确认这在理论上是不好的(非便携式)吗?

Should I better use a cast, a memcpy() or something else? 我是否应该更好地使用演员表,memcpy()或其他东西?

Apart theory, from pragmatic POV is there any REAL portability issue (some incompatible compiler, exotic struct alignment, planned evolutions...)? 从理论上讲,从实用的POV来看,是否存在任何真正的可移植性问题(某些不兼容的编译器,奇异的结构对齐,计划的开发...)?

EDIT: your answers deserve a bit more clarification about my intentions that were: 编辑:关于我的意图,您的答案值得进一步澄清:

  • to let programmer focus on domain specific equations and release them from maintenance of conversion functions (I don't know how to write a generic one, apart cast or memcpy tricks which do not seem more robust) 让程序员专注于特定领域的方程式,并将其从转换函数的维护中释放出来(我不知道该如何写一个通用的,分离的或memcpy的技巧,这些技巧似乎更不健壮)
  • to add a bit more coding security by using struct (fully controlled by compiler) vs arrays (decalaration and access subject to more programmer mistakes) 通过使用结构(由编译器完全控制)与数组(声明和访问受更多程序员错误影响)来增加编码安全性
  • to avoid polluting namespace too much with enum or #define 避免使用enum或#define过度污染名称空间

I need to know 我需要知道

  • how portable/dangerous is my steering off the standard (maybe some compiler with aggressive inlining will use full register solution and avoid any memory exchange ruining the trick), 我偏离标准的可移植性/危险性如何(也许某些具有积极内联的编译器将使用全寄存器解决方案,并避免任何内存交换破坏窍门),
  • and if I missed a standard solution that address above concerns in part or whole. 如果我错过了部分或全部解决上述问题的标准解决方案。

There's no requirement that the two fields in named_states line up the same way as the array elements. 不需要named_states中的两个字段与数组元素排成一行。 There's a good chance that they do, but you've got a compiler dependency there. 他们很有可能这样做,但是那里有编译器依赖性。

Here's a simple implementation in C++ of what you're trying to do: 这是您要尝试执行的C ++中的简单实现:

struct named_or_indexed_states {
    named_or_indexed_states() : speed(indexed[0], position(indexed[1]) { }
    float &speed;
    float &position;
    float indexed[2];
};

If the size increase because of the reference elements is too much, use accessors: 如果由于引用元素导致大小增加太多,请使用访问器:

struct named_or_indexed_states {
    float indexed[2];
    float& speed() { return indexed[0]; }
    float& position() { return indexed[1]; }
};

The compiler will have no problem inlining the accessors, so reading or writing speed() and position() will be just as fast as if they were member data. 编译器将内联访问器毫无问题,因此读取或写入speed()position()速度将与它们是成员数据一样快。 You still have to write those annoying parentheses, though. 但是,您仍然必须写那些令人讨厌的括号。

Only accessing last written member of union is well-defined; 只有访问工会的最后书面成员才能明确定义; the code you presented uses, as far as only standard C (or C++) is concerned, undefined behavior - it may work, but it's wrong way to do it. 就仅涉及标准C(或C ++)而言,您提供的代码使用的是不确定的行为 -可能起作用,但这是错误的方式。 It doesn't really matter that struct uses the same type as the type of array - there may be padding involved, as well as other invisible tricks used by compiler. struct使用与数组类型相同的类型并不重要-可能涉及填充,以及编译器使用的其他隐形技巧。

Some compilers, like GCC, do define it as allowed way to achieve type-punning. 一些编译器,例如GCC,确实将其定义为实现类型绑定的允许方式。 Now the question arises - are we talking about standard C (or C++), or GNU or any other extensions? 现在出现了问题-我们是在谈论标准C(或C ++),GNU还是任何其他扩展?

As for what you should use - proper conversion operators and/or constructors. 至于您应该使用什么-适当的转换运算符和/或构造函数。

This may be a little old-fashioned, but what I would do in this situation is: 这可能有点过时,但是在这种情况下,我要做的是:

enum { 枚举{

F_POSITION, F_POSITION,

F_SPEED, F_SPEED,

F_COUNT }; F_COUNT};

float states[F_COUNT]; 浮动状态[F_COUNT];

Then you can reference them as: states[F_POSITION] and states[F_SPEED]. 然后,您可以将它们引用为:状态[F_POSITION]和状态[F_SPEED]。

That's one way that I might write this. 那是我可能写这个的一种方式。 I'm sure that there are many other possibilities. 我确信还有很多其他可能性。

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

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