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


当前回答

一个简单而有用的例子是....

想象一下:

你有一个uint32_t数组[2],想要访问字节链的第3个和第4个字节。 你可以做*((uint16_t*) &数组[1])。 但遗憾的是,这打破了严格的混叠规则!

但是已知的编译器允许你做以下事情:

union un
{
    uint16_t array16[4];
    uint32_t array32[2];
}

严格来说,这仍然是违反规则的。但是所有已知的标准都支持这种用法。

其他回答

我在几个库中看到过它作为面向对象继承的替代品。

E.g.

        Connection
     /       |       \
  Network   USB     VirtualConnection

如果你想让Connection“类”是上面的任何一个,你可以这样写:

struct Connection
{
    int type;
    union
    {
        struct Network network;
        struct USB usb;
        struct Virtual virtual;
    }
};

libinfinity示例:http://git.0x539.de/?p=infinote.git;a=blob;f=libinfinity/common/inf-session.c;h=3e887f0d63bd754c6b5ec232948027cbbf4d61fc;hb=HEAD#l74

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

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的值,因为它们都共享相同的内存位置。

有很多用法。只需执行grep union /usr/include/*或类似目录。大多数情况下,联合被包装在结构中,结构的一个成员告诉联合中的哪个元素可以访问。例如,为现实生活的实现签出man elf。

这是基本原则:

struct _mydata {
    int which_one;
    union _data {
            int a;
            float b;
            char c;
    } foo;
} bar;

switch (bar.which_one)
{
   case INTEGER  :  /* access bar.foo.a;*/ break;
   case FLOATING :  /* access bar.foo.b;*/ break;
   case CHARACTER:  /* access bar.foo.c;*/ break;
}