1.联合与结构
上一节中我们使用struct关键词,组合不同的类型让它们成为一个新的类型。
例如,我们想组合char、short、long long,可以像如下代码写法。
struct {
char c;
short s;
long long ll;
}s;
对于结构struct的讨论在上一节已经够多了。在一节中,我们讨论和结构语法类似的联合,关键词为union。
联合char、short、long long,可以像如下代码写法。
union {
char c;
short s;
long long ll;
}u;
联合的语法非常类似于结构的语法,几乎仅仅换了一个关键词而已。让我们来看看,它们之间有什么差别?
我们先使用sizeof分别测试一下它们的大小。
struct {
char c;
short s;
long long ll;
}s;
union {
char c;
short s;
long long ll;
}u;
printf("sizeof s %d\n", sizeof(s));
printf("sizeof u %d\n", sizeof(u));

结构s测得大小为16,而联合u测得大小为8。
对于结构来说,char占用1字节,short占用2个字节。long long占用8字节。如果它们相邻紧密排列,按理说会占用11个字节。

似乎两个结果都有些奇怪。让我们将其成员的地址打印出来,详细地分析一下,它们的内存排布情况。
struct {
char c;
short s;
long long ll;
}s;
union {
char c;
short s;
long long ll;
}u;
printf("&s.c %d \n", &s.c);
printf("&s.s %d \n", &s.s);
printf("&s.ll %d \n\n", &s.ll);
printf("&u.c %d \n", &u.c);
printf("&u.s %d \n", &u.s);
printf("&u.ll %d \n", &u.ll);

结构s的成员c的首地址为8649904。
结构s的成员s的首地址为8649906。
结构s的成员ll的首地址为8649912。

根据地址,我们画出了结构s各个成员的内存排布情况。char与short只留空了一个字节,而short与long long之间留空了4个字节。
这种现象被称为内存对齐,虽然会浪费一些内存空间,对齐后的数据能够被更快的访问。
内存对齐有一套规则,这里我们并不展开讨论结构中的成员是如何对齐的了。我们接着往下看,看看联合中的成员的内存排布情况。
联合u的成员c的首地址为8649896。
联合u的成员s的首地址为8649896。
联合u的成员ll的首地址为8649896。
似乎联合中成员的首地址是重叠的。

没错,联合中的成员首地址是重叠的,这意味着联合的大小为联合中最大成员的大小。
接下来,我们进一步研究联合的性质。