什么时候应该使用工会?我们为什么需要它们?
当前回答
联合通常用于整数和浮点数的二进制表示之间的转换:
union
{
int i;
float f;
} u;
// Convert floating-point bits to integer:
u.f = 3.14159f;
printf("As integer: %08x\n", u.i);
尽管根据C标准,这在技术上是未定义的行为(您只应该阅读最近编写的字段),但它将在几乎任何编译器中以定义良好的方式起作用。
联合有时也被用来实现C语言中的伪多态性,通过给一个结构一些标记来指示它包含什么类型的对象,然后将可能的类型联合在一起:
enum Type { INTS, FLOATS, DOUBLE };
struct S
{
Type s_type;
union
{
int s_ints[2];
float s_floats[2];
double s_double;
};
};
void do_something(struct S *s)
{
switch(s->s_type)
{
case INTS: // do something with s->s_ints
break;
case FLOATS: // do something with s->s_floats
break;
case DOUBLE: // do something with s->s_double
break;
}
}
这使得struct S的大小只有12字节,而不是28字节。
其他回答
一个简单而有用的例子是....
想象一下:
你有一个uint32_t数组[2],想要访问字节链的第3个和第4个字节。 你可以做*((uint16_t*) &数组[1])。 但遗憾的是,这打破了严格的混叠规则!
但是已知的编译器允许你做以下事情:
union un
{
uint16_t array16[4];
uint32_t array32[2];
}
严格来说,这仍然是违反规则的。但是所有已知的标准都支持这种用法。
很难想出需要这种灵活结构的特定场合,也许在发送不同大小消息的消息协议中,但即使在这种情况下,也可能有更好、更适合程序员的替代方案。
联合有点像其他语言中的变体类型——它们一次只能保存一个东西,但这个东西可以是int型,浮点型等,这取决于你如何声明它。
例如:
typedef union MyUnion MYUNION;
union MyUnion
{
int MyInt;
float MyFloat;
};
MyUnion将只包含一个int或一个float,这取决于你最近设置的。所以这样做:
MYUNION u;
u.MyInt = 10;
U现在持有int = 10;
u.MyFloat = 1.0;
U现在持有一个等于1.0的浮点数。它不再持有int型。显然,如果你尝试printf("MyInt=%d" u.MyInt);那么你可能会得到一个错误,尽管我不确定具体的行为。
联合的大小由其最大字段的大小决定,在本例中为float。
联合允许互斥的数据成员共享相同的内存。当内存比较稀缺时,例如在嵌入式系统中,这是非常重要的。
示例如下:
union {
int a;
int b;
int c;
} myUnion;
这个联合将占用一个int值的空间,而不是3个独立的int值。如果用户设置了a的值,然后设置了b的值,它将覆盖a的值,因为它们都共享相同的内存位置。
当您希望对由硬件、设备或网络协议定义的结构进行建模时,或者当您要创建大量对象并希望节省空间时,可以使用联合。不过,在95%的情况下,你真的不需要它们,坚持使用易于调试的代码。
工会是伟大的。我所见过的联合的一个聪明用法是在定义事件时使用它们。例如,您可能决定一个事件是32位的。
现在,在这32位中,您可能希望将前8位指定为事件发送方的标识符……有时你要把事件作为一个整体来处理,有时你要剖析它并比较它的组成部分。工会让你可以灵活地做到这两点。
union Event { unsigned long eventCode; unsigned char eventParts[4]; };