联合体的声明和结构体类似,但他的行为却和结构体不同。联合体所有成员引用的是内存中相同位置。当你想在不同时刻把不同东西存在同一个位置时可以使用联合体。
看一个简单的例子。
1 |
<span class="token keyword">union</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">float</span> f<span class="token punctuation">;</span> <span class="token keyword">int</span> i<span class="token punctuation">;</span> <span class="token punctuation">}</span>fi<span class="token punctuation">;</span> fi<span class="token punctuation">.</span>f <span class="token operator">=</span> <span class="token number">3.14159</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"fi.i = %d\n"</span><span class="token punctuation">,</span> fi<span class="token punctuation">.</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span> |
在一个浮点型和整形都是32位的机器上,变量fi只占据内存中一个32位字,当f被使用时,这个字就作为浮点型值被访问;单i被使用时,这个字就作为整形值被访问。简单说就是同一块内存,被翻译成不同类型的数据,如何翻译取决于定义的数据类型。
上面程序运行结果。
1 |
fi<span class="token punctuation">.</span>i <span class="token operator">=</span> <span class="token number">1078530000</span> |
联合体的作用
BASIC需要记住程序使用的变量值,他提供了几种不同类型的变量。每个变量的类型必须和他的值一起存储。这里定义了一个结构用来存储这种信息,但是效率并不高。
1 |
<span class="token keyword">struct</span> VARIABLE<span class="token punctuation">{<!-- --></span> <span class="token keyword">enum</span> <span class="token punctuation">{<!-- --></span>INT<span class="token punctuation">,</span> FLOAT<span class="token punctuation">,</span>STRING<span class="token punctuation">}</span> type<span class="token punctuation">;</span> <span class="token keyword">int</span> int_value<span class="token punctuation">;</span> <span class="token keyword">float</span> float_value<span class="token punctuation">;</span> <span class="token keyword">char</span> <span class="token operator">*</span>string_value<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
当BASIC程序中一个变量被创建时,就创建一个这种类型的结构用来记录变量的类型,根据变量的类型,把变量的值存储在三个字段中的一个。这个结构的低效之处在于,每次都有两个字段被浪费,因为一个变量只有一种数据类型。
联合可以减少这种浪费,把三个字段存储在同一块内存区域并不会产生冲突,在某个时刻,联合中只有一个字段会被使用。
1 |
<span class="token keyword">struct</span> VARIABLE <span class="token punctuation">{<!-- --></span> <span class="token keyword">enum</span> <span class="token punctuation">{<!-- --></span> INT<span class="token punctuation">,</span> FLOAT<span class="token punctuation">,</span> STRING<span class="token punctuation">}</span> type<span class="token punctuation">;</span> <span class="token keyword">union</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">int</span> i<span class="token punctuation">;</span> <span class="token keyword">float</span> f<span class="token punctuation">;</span> <span class="token keyword">char</span> <span class="token operator">*</span>s<span class="token punctuation">;</span> <span class="token punctuation">}</span>value<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
如果联合体的各个成员具有不同的变量,联合的长度等于最长成员的长度。
联合体-变体记录
内存中某个特定的区域将在不同时刻存储不同类型的值,在有些情况下,这些值比简单的整型或浮点型更为复杂,它们每一个都是一个完整的结构。
这个例子取自一个存货系统,他记录两个不同实体:零件(part)和装配件(subassembly)。
1 |
<span class="token keyword">struct</span> PARTINFO <span class="token punctuation">{<!-- --></span> <span class="token keyword">int</span> cost<span class="token punctuation">;</span> <span class="token keyword">int</span> supplier<span class="token punctuation">;</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">struct</span> SUBASSYINFO <span class="token punctuation">{<!-- --></span> <span class="token keyword">int</span> n_parts<span class="token punctuation">;</span> <span class="token keyword">struct</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">char</span> partno<span class="token punctuation">[</span><span class="token number">10</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">short</span> quan<span class="token punctuation">;</span> <span class="token punctuation">}</span>parts<span class="token punctuation">[</span>MAXPARTS<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
接下来的存货(inventory)记录了包含每个项目的一般信息,包括一个联合,或者用于存储零件信息,或者用于存储转配件信息。
1 |
<span class="token keyword">struct</span> INVREC <span class="token punctuation">{<!-- --></span> <span class="token keyword">char</span> partno<span class="token punctuation">[</span><span class="token number">10</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">int</span> quan<span class="token punctuation">;</span> <span class="token keyword">enum</span> <span class="token punctuation">{<!-- --></span>PART<span class="token punctuation">,</span> SUBASSY<span class="token punctuation">}</span> type<span class="token punctuation">;</span> <span class="token keyword">union</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">struct</span> PARTINFO part<span class="token punctuation">;</span> <span class="token keyword">struct</span> SUBASSYINFO subassy<span class="token punctuation">;</span> <span class="token punctuation">}</span>info<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
在一个成员长度不同的联合体里,分配给联合体的内存数量取决于最大成员长度。如果这些成员长度相差悬殊,当存储长度较短成员时会浪费内存,在这种情况下更好的方法是在联合体重存储指向不同成员的指针,而不是存储成员本身。所有指针的长度都是相同的,这样就解决内存浪费的问题。当决定存储那个成员时,分配正确数量的内存来存储该成员。
联合的初始化
联合变量可以被初始化,但这个初始值必须是联合的第一个成员的类型,而且它必须位于一对花括号内。例如,
1 |
<span class="token keyword">union</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">int</span> a<span class="token punctuation">;</span> <span class="token keyword">float</span> b<span class="token punctuation">;</span> <span class="token keyword">char</span> c<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>x <span class="token operator">=</span> <span class="token punctuation">{<!-- --></span><span class="token number">5</span><span class="token punctuation">}</span><span class="token punctuation">;</span> |
x.a 初始化为5.
我们不能把这个变量初始化为一个浮点型或者字符值。如果给出的类型是任何其他类型的值,会被强制转化为整型并赋值给x.a。