union foo {
int a; // can't use both a and b at once
char b;
} foo;
struct bar {
int a; // can use both a and b simultaneously
char b;
} bar;
union foo x;
x.a = 3; // OK
x.b = 'c'; // NO! this affects the value of x.a!
struct bar y;
y.a = 3; // OK
y.b = 'c'; // OK
对于联合体,你只能使用其中一个元素,因为它们都被存储在同一个地方。这使得它在你想存储可能是几种类型之一的东西时非常有用。另一方面,结构体为其每个元素都有一个单独的内存位置,它们都可以被一次性使用。
举个具体的例子,我不久前在做一个Scheme解释器,我基本上是把Scheme数据类型叠加到C数据类型上的。这涉及到在一个结构中存储一个表示值类型的枚举和一个存储该值的联盟。
编辑:如果你想知道把x.b设置为'c'会把x.a的值变成什么,从技术上讲,它是未定义的。在大多数现代机器上,一个char是1个字节,一个int是4个字节,所以给x.b的值'c'也给x.a的第一个字节同样的值。
打印
为什么这两个值是一样的?因为int 3的最后3个字节都是0,所以它也被读作99。如果我们为x.a输入一个更大的数字,你会发现情况并非总是如此。
打印
为了仔细了解实际的内存值,让我们设置并打印出十六进制的数值。
打印
你可以清楚地看到0x22覆盖了0xEF的地方。
BUT
在C语言中,int中字节的顺序是没有定义的。这个程序在我的Mac上用0x22覆盖了0xEF,但在其他平台上,它会覆盖0xDE,因为组成int的字节的顺序是相反的。因此,在编写程序时,你千万不要依赖覆盖联盟中的特定数据的行为,因为它不具有可移植性。
关于字节排序的更多阅读,请查看endianness。
"union"和"struct"是C语言的结构。谈论它们之间的"操作系统级别"差异是不恰当的,因为如果你使用一个或另一个关键词,是编译器*产生不同的代码。
一个结构分配其中所有元素的总大小。
一个联盟只分配其最大成员所需的内存。