联盟 - 无用的时代错误或有用的老派伎俩?

Tre*_*ith 20 c c++ unions data-structures

我最近遇到了一本很棒的数据结构书," 数据结构使用C "(c)1991,当地图书馆书籍2美元.正如本书的标题所暗示的,本书涵盖了使用C编程语言的数据结构.

我知道这本书已经过时,但可能会包含许多我在其他地方都不会遇到的高级C主题.

确实在5分钟内我找到了一些我不知道的关于C的内容.我遇到了一个关于union关键字的部分,我意识到我从未使用它,也没见过任何代码.我很高兴能够学到一些有趣的东西并迅速买下这本书.

对于那些不了解联盟是什么的人,本书使用一个好的比喻来解释:

要完全理解联合的概念,有必要检查它的实现.结构可以被视为存储器区域的路线图.它定义了如何解释内存.联合为同一内存区域提供了几种不同的路线图,程序员有责任确定当前使用的路线图.实际上,编译器会分配足够的存储空间来包含union的最大成员.然而,路线图确定了如何解释存储.

我可以很容易地想出我会使用联盟的人为的情况或黑客.(但我对人为的情况或黑客不感兴趣...)

您是否曾使用或看过使用Union解决问题的实现**比不使用Union更优雅**?

如果你快速解释为什么使用union比不使用union更好/更容易,可以增加额外的奖励.

Luc*_*ero 24

UNION在非OOP世界中实现某种多态性.通常,您有一个常见的部分,根据该部分,您使用其余的UNION.因此,在没有OOP语言并且想要避免过多指针算术的情况下,在某些情况下,联合会更加优雅.

  • @HappyYellowFace这应该是新的URL:http://wiki.libsdl.org/SDL_Event?highlight =%28%5CbCategoryStruct%5Cb%29%7C%28SDLStructTemplate%29 (4认同)

sco*_*zer 18

这对于设置寄存器而不是移位/掩码操作非常有用:

typedef union {
    unsigned int as_int; // Assume this is 32-bits
    struct {
        unsigned int unused1 : 4;
        unsigned int foo : 4;
        unsigned int bar : 6;
        unsigned int unused2 : 2;
        unsigned int baz : 3;
        unsigned int unused3 : 1;
        unsigned int quux : 12;
    } field;
} some_reg;
Run Code Online (Sandbox Code Playgroud)

注意:打包的方式与机器有关.

some_reg reg;
reg.field.foo = 0xA;
reg.field.baz = 0x5;
write_some_register(some_address, reg.as_int);
Run Code Online (Sandbox Code Playgroud)

我可能在那里的某个地方吹了一些语法,我的C生锈了:)

编辑:

顺便说一句,这也是相反的方式:

reg.as_int = read_some_register(some_address);
if(reg.field.bar == BAR_ERROR1) { ...
Run Code Online (Sandbox Code Playgroud)

  • @scottfrazer,如果您的代码有效……这是调整网络数据包中位字段的非常有用的方法!它不仅 100% 定义了数据包结构并使代码更清晰......而且它使实现代码更易于阅读,因为您只是设置字段而不是做很多(掩码 n 位,移位 M 位,或n 位与 uint32_t ... 等一起返回)。 (2认同)
  • 事实上,克里斯托是对的。读取工会的任何成员但最后一个写入是未定义的。如果还没有写入,读取其中任何一个都是 UB。它既不是未指定的(“未记录的”)也不是实现定义的(“记录的”)行为;崩溃是绝对允许的。当 CPU 具有用于 int 和 float 变量的不同寄存器并且联合包含两者时,这可能尤其明显。例如 "uf = 1.0+1.2; printf("%d", ui);" 可能不会导致在 printf 之前将浮点寄存器写回内存。 (2认同)

Meh*_*ari 10

实际上,当你编写诸如设备驱动程序之类的东西(struct你想要发送到可以有几种类似但不同格式的设备)并且你需要精确的内存排列时,它是一个很棒的工具......


小智 8

您应该知道在C++中它们不是一个很好的解决方案,因为只有POD(普通旧数据)类型可以放在一个联合中.如果您的类具有构造函数,析构函数,包含具有构造函数和/或析构函数的类(以及大约一百万个其他陷阱),则它不能是联合的成员.


sha*_*oth 6

我认为,Union是在C/C++中实现类似VARIANT的数据类型的最简单方法.


mar*_*h44 5

它通常用于数据传输协议的规范中,您希望避免在数据结构中浪费空间.它允许通过为多个互斥选项使用相同的空间来保存存储空间.

例如:

enum PacketType {Connect, Disconnect};
struct ConnectPacket {};
struct DisconnectPacket {};
struct Packet
{
    // ...
    // various common data
    // ...
    enum PacketType type;
    union
    {
        ConnectPacket connect;
        DisconnectPacket disconnect;
    } payload;
};
Run Code Online (Sandbox Code Playgroud)

ConnectPacket和DisconnectPacket结构占用相同的空间,但这没关系,因为数据包不能同时是两种类型.枚举值用于确定联合的哪个部分正在使用中.使用union允许我们避免重复Packet结构的公共部分.