什么是联合体?

10

最近我在使用Windows时发现,很多数据结构被定义为struct,并且有union作为成员变量。例如Windows中的EVT_VARIANT

我不理解这样做的目的是什么。


那么,是什么引起了你的问题呢?联合体的目的是共享内存区域,即在同一内存区域中不同时间存储不同类型的数据。这可以在任何地方工作,即联合体可以单独使用,也可以用作结构体的成员。在结构体内部使用联合体并没有什么特别或奇怪的地方。因此,不清楚你为什么会问这个问题。 - AnT stands with Russia
5个回答

16

当一个struct包含union成员时,通常是为了节省空间。如果这个struct可以是某些子类型,而只有某些成员是有效的,则使用union是不浪费空间的好方法。

例如:

enum NumberKind {
  Integer, 
  FloatingPoint 
};

struct Number {
  NumberKind kind;
  union {
    int integerValue;
    float floatValue;
  };
};
在这个场景中,我定义了一个“结构体(Number)”,它可以拥有浮点数和整数类型的数字值。同时拥有浮点数和整数类型是无效的,因此,我创建了一个“联合体(union)”,使得存储最大值的大小等于两者之间的较大值,避免了对内存空间的浪费。
上述内容的示例用法如下所示。
void PrintNumber(Number value) {
  if (value.kind == Integer) {
    printf("%d\n", value.integerValue);
  } else {
    printf("%f\n", value.floatValue);
  }
}

谢谢您的解释,但是能否更详细地说明一下它的用法呢? - Avinash
1
@Avinash 添加了一个示例用例。 - JaredPar
@JaredPar 我认为那个给你点踩的人需要支付一个点数来进行踩。 - Foo Bah
@Foo Bah:如果那个踩票者真的像你说的那样,为什么他们不在评论中解释呢? - john
2
这是一个纯粹的C++回答,在目前标记为C和C++的问题中。也许投票者将其视为C代码而不是C++代码?也许答案应该解释一下这段代码所展示的C和C++之间的差异? - Jonathan Leffler
显示剩余6条评论

3
假设你有一个结构体,它保存了数据包。数据包中的数据可能是几种不同的类型,因此你需要在一个名为type的成员中存储类型信息。为了读取数据包中的数据,你需要先检查类型,然后读取相应的数据成员,该成员应该包含数据包中的数据。
如果没有联合(union),那么数据结构将如下所示:
struct data {
    type_t type;

    int number;
    char * string;
    double fraction;
    long long big_number;
}

这将是一个相当大的数据结构。它需要足够的空间来存储每种可能的数据类型。但你只会在任何时候有一个成员包含有用信息,因此这显得有些多余。

如果我们使用联合:

struct data {
    type_t type;

    union payload {
         int number;
         char * string;
         double fraction;
         long long big_number;
    }
}

那么,结构体只包含足够存储类型和其中一个有效载荷成员的空间(即,您将分配与type_t大小加上最大可能有效载荷成员大小相等的内存量)。这样可以节省大量空间并且更加高效。

但是,您必须小心,因为如果有效载荷包含int类型,您仍然可以将其读取为double类型。您的程序尝试错误地解释数据时,您可能会得到极其奇怪的数字。


3
作为64KB内存时代的遗物,在C++中有一种可以让多个变量共享同一块内存(但显然不是同时)的设施。这称为联合体,您可以使用以下四种基本方法之一:
- 您可以使用它使变量A在程序的某个点占用一个内存块,而稍后由不同类型的变量B占用该内存块,因为A不再需要。我建议您不要这样做。这种排列隐含着错误的风险,不值得冒险。您可以通过动态分配内存来实现相同的效果。 - 或者,在程序中可能需要大量数据的情况下,您无法提前知道数据类型——它将由输入数据确定。在这种情况下,我也建议您不要使用联合体,因为您可以使用几个不同类型的指针并动态分配内存来实现相同的结果。 - 联合体的第三种可能用途是您偶尔需要的一种方式——当您想以两种或更多不同的方式解释相同数据时。例如,当您有一个long类型的变量,并且希望将其视为两个short类型的值时,就会发生这种情况。Windows有时会将两个short值打包在传递给函数的long类型参数的单个参数中。另一个例子是当您希望将包含数字数据的内存块视为字节字符串以移动它时。 - 您可以使用联合体作为传递对象或数据值的一种手段,其中您无法提前知道其类型将是什么。联合体可以提供存储可能具有的任何一种类型的范围。
如果您认为我在解释联合体及其可能应用方面很有天赋,那么我不能为此负责。(: 这些信息来自Ivor Horton的Beginning Visual C++ 2010,我碰巧把它放在桌子上。希望这对您有所帮助。

1

在结构体中使用联合技术通常是当您想要一种变体风格的结构时。它通常伴随着类型标识符,用于确定联合中要检查的项目。它也可以以相反的方式出现,例如在*NIX上的Xlib中,它是一个带有结构体的联合,所有结构体之间的第一个成员都相同,定义了哪个结构体具有所需的数据。


0

联合意味着它的成员可以作为其可能的值之一。 在下面的例子中,你可以看到每个成员的值。 但是这个联合可以是其他结构的成员,在那里只需要指定一个值-要么是浮点数,要么是整数,而不是两者都有。 希望这对你有所帮助。

  union {
          float u_f;
          int u_i;
  }var;

  var.u_f = 23.5;
  printf("value is %f\n", var.u_f);
  var.u_i = 5;
  printf("value is %d\n", var.u_i)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接