什么时候应该使用工会?我们为什么需要它们?


当前回答

COM接口中使用的VARIANT呢?它有两个字段——“type”和一个包含实际值的联合,该值根据“type”字段进行处理。

其他回答

低级系统编程就是一个合理的例子。

IIRC中,我使用联合将硬件寄存器分解为组件位。因此,您可以访问一个8位寄存器(在我这样做的那天;-)到组件位。

(我忘记了确切的语法,但是……)这种结构将允许控制寄存器作为control_byte或通过单个位来访问。对于给定的字节顺序,确保位映射到正确的寄存器位是很重要的。

typedef union {
    unsigned char control_byte;
    struct {
        unsigned int nibble  : 4;
        unsigned int nmi     : 1;
        unsigned int enabled : 1;
        unsigned int fired   : 1;
        unsigned int control : 1;
    };
} ControlRegister;

很难想出需要这种灵活结构的特定场合,也许在发送不同大小消息的消息协议中,但即使在这种情况下,也可能有更好、更适合程序员的替代方案。

联合有点像其他语言中的变体类型——它们一次只能保存一个东西,但这个东西可以是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的值,因为它们都共享相同的内存位置。

联合通常用于整数和浮点数的二进制表示之间的转换:

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字节。

工会是伟大的。我所见过的联合的一个聪明用法是在定义事件时使用它们。例如,您可能决定一个事件是32位的。

现在,在这32位中,您可能希望将前8位指定为事件发送方的标识符……有时你要把事件作为一个整体来处理,有时你要剖析它并比较它的组成部分。工会让你可以灵活地做到这两点。

union Event
{
  unsigned long eventCode;
  unsigned char eventParts[4];
};