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


当前回答

在学校里,我是这样使用联合的:

typedef union
{
  unsigned char color[4];
  int       new_color;
}       u_color;

我用它来更容易地处理颜色,而不是使用>>和<<操作符,我只需要遍历我的char数组的不同索引。

其他回答

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

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

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

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

这里有一个来自我自己代码库的联合的例子(来自记忆和转述,所以可能不准确)。它被用来在我构建的解释器中存储语言元素。例如,以下代码:

set a to b times 7.

由以下语言元素组成:

[设置]符号 可变[a] 符号[到] 可变[b] 符号[时报] 康斯坦[7] 符号[。]

语言元素被定义为“#define”值,如下:

#define ELEM_SYM_SET        0
#define ELEM_SYM_TO         1
#define ELEM_SYM_TIMES      2
#define ELEM_SYM_FULLSTOP   3
#define ELEM_VARIABLE     100
#define ELEM_CONSTANT     101

下面的结构被用来存储每个元素:

typedef struct {
    int typ;
    union {
        char *str;
        int   val;
    }
} tElem;

然后,每个元素的大小是最大联合的大小(typ为4字节,联合为4字节,尽管这些是典型值,但实际大小取决于实现)。

为了创建一个“set”元素,你可以使用:

tElem e;
e.typ = ELEM_SYM_SET;

为了创建一个“variable[b]”元素,你可以使用:

tElem e;
e.typ = ELEM_VARIABLE;
e.str = strdup ("b");   // make sure you free this later

为了创建一个常量[7]元素,你可以使用:

tElem e;
e.typ = ELEM_CONSTANT;
e.val = 7;

你可以很容易地将其扩展为包含浮点数(float flt)或有理数(struct ratnl {int num;Int denom;})和其他类型。

基本前提是str和val在内存中不是连续的,它们实际上是重叠的,所以这是一种在同一块内存上获得不同视图的方法,如图所示,其中结构基于内存位置0x1010,整数和指针都是4字节:

       +-----------+
0x1010 |           |
0x1011 |    typ    |
0x1012 |           |
0x1013 |           |
       +-----+-----+
0x1014 |     |     |
0x1015 | str | val |
0x1016 |     |     |
0x1017 |     |     |
       +-----+-----+

如果只是在一个结构中,它看起来会是这样的:

       +-------+
0x1010 |       |
0x1011 |  typ  |
0x1012 |       |
0x1013 |       |
       +-------+
0x1014 |       |
0x1015 |  str  |
0x1016 |       |
0x1017 |       |
       +-------+
0x1018 |       |
0x1019 |  val  |
0x101A |       |
0x101B |       |
       +-------+

包含不同记录类型的文件。 包含不同请求类型的网络接口。

看一下这个:X.25缓冲区命令处理

许多可能的X.25命令中的一个被接收到缓冲区中,并通过使用所有可能结构的UNION进行适当的处理。

许多答案都涉及从一种类型转换到另一种类型。我从具有相同类型的联合中得到最多的使用(即在解析串行数据流时)。它们允许解析/构造一个有框架的包变得很简单。

typedef union
{
    UINT8 buffer[PACKET_SIZE]; // Where the packet size is large enough for
                               // the entire set of fields (including the payload)

    struct
    {
        UINT8 size;
        UINT8 cmd;
        UINT8 payload[PAYLOAD_SIZE];
        UINT8 crc;
    } fields;

}PACKET_T;

// This should be called every time a new byte of data is ready 
// and point to the packet's buffer:
// packet_builder(packet.buffer, new_data);

void packet_builder(UINT8* buffer, UINT8 data)
{
    static UINT8 received_bytes = 0;

    // All range checking etc removed for brevity

    buffer[received_bytes] = data;
    received_bytes++;

    // Using the struc only way adds lots of logic that relates "byte 0" to size
    // "byte 1" to cmd, etc...
}

void packet_handler(PACKET_T* packet)
{
    // Process the fields in a readable manner
    if(packet->fields.size > TOO_BIG)
    {
        // handle error...
    }

    if(packet->fields.cmd == CMD_X)
    {
        // do stuff..
    }
}

编辑 关于字节序和结构填充的评论是有效的,而且非常值得关注。我几乎完全在嵌入式软件中使用了这段代码,其中大部分我都可以控制管道的两端。