186 lines
15 KiB
HTML
186 lines
15 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh" dir="ltr" class="client-nojs" xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh">
|
|
<head><meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<title>联合体声明</title>
|
|
<link rel="stylesheet" href="ext.css" />
|
|
<link rel="stylesheet" href="site_modules.css" />
|
|
</head>
|
|
<body class="mediawiki ltr sitedir-ltr ns-0 ns-subject page-c_language_union skin-cppreference2 action-view cpp-navbar">
|
|
<div id="cpp-content-base">
|
|
<div id="content"><a id="top"></a>
|
|
<h1 id="firstHeading" class="firstHeading">联合体声明</h1>
|
|
<div id="bodyContent">
|
|
<div id="contentSub"><span class="subpages">< <a href="c.html">c</a>‎ | <a href="c-language.html">language</a></span></div>
|
|
<div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr" xml:lang="zh">
|
|
<p>联合体是由一序列的成员所组成的类型,成员的存储重叠(与结构体相反,结构体是由一序列的成员所构成的类型,成员的存储以顺序分配)。在任一时刻,最多能在联合体中存储其一个成员的值。</p>
|
|
<p>联合体的<a href="c-language-declarations.html">类型说明符</a>与 <a href="c-language-struct.html"><code>struct</code></a> 类型说明符相同,只是所用的关键词有别。</p>
|
|
<h3><span class="mw-headline" id=".E8.AF.AD.E6.B3.95">语法</span></h3>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>union</b></code> <span class="t-spar">属性声明符序列</span><span class="t-mark">(可选)</span> <span class="t-spar">名字</span><span class="t-mark">(可选)</span> <code><b>{</b></code> <span class="t-spar">结构体声明列表</span> <code><b>}</b></code></td>
|
|
<td>(1)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>union</b></code> <span class="t-spar">属性声明符序列</span><span class="t-mark">(可选)</span> <span class="t-spar">名字</span></td>
|
|
<td>(2)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-par-begin">
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">名字</span></td>
|
|
<td>-</td>
|
|
<td>正在定义的联合体名称</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">结构体声明列表</span></td>
|
|
<td>-</td>
|
|
<td>任意数量的变量声明、<a href="c-language-bit_field.html">位域</a>声明和<a href="c-language-_Static_assert.html">静态断言</a>声明。不允许不完整类型的成员和函数类型的成员。</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">属性声明符序列</span></td>
|
|
<td>-</td>
|
|
<td><span class="t-mark-rev t-since-c23">(C23)</span>可选的<a href="c-language-attributes.html">属性</a>列表,应用到联合体类型,若这种形式不后随 <code><b>;</b></code> (即不是前置声明)则对于 <span class="t-v">(2)</span> 不允许。</td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<p>联合体只大到足以保有其最大成员(亦可能添加额外的尾随填充字节)。其他成员被分配于与该最大成员一部分相同的字节中。</p>
|
|
<p>能转型指向联合体的指针为指向它每个成员的指针(若联合体拥有位域成员,则能转型指向联合体的指针为指向位域底层类型的指针)。类似地,指向结构体任何成员的指针都能被转型为指向整个结构体的指针。</p>
|
|
<p>若用于访问内容的联合体成员不同于上次用于存储值的成员,则转译被存储值的对象表示为新类型的对象表示(这被称为<i>类型双关</i>)。若新类型的大小大于上次写入的类型大小,则多出的字节内容是未指明的(而且可以是陷阱表示)。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c11">
|
|
<td>
|
|
<p>类似结构体,类型为不带 <span class="t-spar">name</span> 的联合体的无名联合体成员被称为<i>匿名联合体</i>。每个匿名联合体的成员被认为是外围结构体或联合体的成员。若外围结构体或联合体亦为匿名,则递归调用此规则。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw1">struct</span> v <span class="br0">{</span>
|
|
<span class="kw1">union</span> <span class="br0">{</span> <span class="co1">// 匿名联合体</span>
|
|
<span class="kw1">struct</span> <span class="br0">{</span> <span class="kw4">int</span> i, j<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 匿名结构体</span>
|
|
<span class="kw1">struct</span> <span class="br0">{</span> <span class="kw4">long</span> k, l<span class="sy4">;</span> <span class="br0">}</span> w<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span> m<span class="sy4">;</span>
|
|
<span class="br0">}</span> v1<span class="sy4">;</span>
|
|
|
|
v1.<span class="me1">i</span> <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> <span class="co1">// 合法</span>
|
|
v1.<span class="me1">k</span> <span class="sy1">=</span> <span class="nu0">3</span><span class="sy4">;</span> <span class="co1">// 非法:内层结构体不是匿名的</span>
|
|
v1.<span class="me1">w</span>.<span class="me1">k</span> <span class="sy1">=</span> <span class="nu0">5</span><span class="sy4">;</span> <span class="co1">// 合法</span></pre></div>
|
|
</div>
|
|
<p>类似结构体,若不以任何具名成员(包含经由匿名嵌套结构体或联合体获得的成员)定义联合体,则程序行为未定义。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c11">(C11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E5.85.B3.E9.94.AE.E8.AF.8D">关键词</span></h3>
|
|
<p><a href="c-keyword-union.html"><tt>union</tt></a></p>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<p>关于结构体和联合体初始化的规则,见<a href="c-language-struct_initialization.html">结构体初始化</a>。</p>
|
|
<h3><span class="mw-headline" id=".E7.A4.BA.E4.BE.8B">示例</span></h3>
|
|
<div class="t-example">
|
|
<div class="t-example-live-link"></div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="co2">#include <stdio.h></span>
|
|
<span class="co2">#include <stdint.h></span>
|
|
<span class="co2">#include <assert.h></span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">union</span> S <span class="br0">{</span>
|
|
<a href="c-types-integer.html"><span class="kw122">uint32_t</span></a> u32<span class="sy4">;</span>
|
|
<a href="c-types-integer.html"><span class="kw121">uint16_t</span></a> u16<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span><span class="sy4">;</span>
|
|
<a href="c-types-integer.html"><span class="kw120">uint8_t</span></a> u8<span class="sy4">;</span>
|
|
<span class="br0">}</span> s <span class="sy1">=</span> <span class="br0">{</span><span class="nu12">0x12345678</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// s.u32 现为活跃成员</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"Union S has size %zu and holds %x<span class="es1">\n</span>"</span>, <span class="kw4">sizeof</span> s, s.<span class="me1">u32</span><span class="br0">)</span><span class="sy4">;</span>
|
|
s.<span class="me1">u16</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span> <span class="sy1">=</span> <span class="nu12">0x0011</span><span class="sy4">;</span> <span class="co1">// s.u16 现为活跃成员</span>
|
|
<span class="co1">// 从 s.u32 或 s.u8 的读取转译对象表示</span>
|
|
<span class="co1">// printf("s.u8 is now %x\n", s.u8); // 未指定,典型结果是 11 或 00</span>
|
|
<span class="co1">// printf("s.u32 is now %x\n", s.u32); // 未指定,典型结果是 12340011 或 00115678</span>
|
|
|
|
<span class="co1">// 指向联合体所有成员的指针彼此间比较相等,也与指向联合体的指针比较相等</span>
|
|
<a href="c-error-assert.html"><span class="kw407">assert</span></a><span class="br0">(</span><span class="br0">(</span><a href="c-types-integer.html"><span class="kw120">uint8_t</span></a><span class="sy2">*</span><span class="br0">)</span><span class="sy3">&</span>s <span class="sy1">==</span> <span class="sy3">&</span>s.<span class="me1">u8</span><span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 此联合体拥有尾随的 3 个填充字节</span>
|
|
<span class="kw1">union</span> pad <span class="br0">{</span>
|
|
<span class="kw4">char</span> c<span class="br0">[</span><span class="nu0">5</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 占据 5 字节</span>
|
|
<span class="kw4">float</span> f<span class="sy4">;</span> <span class="co1">// 占据 4 字节,隐含对齐 4</span>
|
|
<span class="br0">}</span> p <span class="sy1">=</span> <span class="br0">{</span>.<span class="me1">f</span> <span class="sy1">=</span> <span class="nu16">1.23</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 大小为 8 以满足 float 的对齐</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"size of union of char[5] and float is %zu<span class="es1">\n</span>"</span>, <span class="kw4">sizeof</span> p<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>可能的输出:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="text source-text">
|
|
<pre class="de1">Union S has size 4 and holds 12345678
|
|
size of union of char[5] and float is 8</pre></div>
|
|
</div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.BC.95.E7.94.A8">引用</span></h3>
|
|
<div class="t-ref-std-17">
|
|
<ul>
|
|
<li>C17 标准(ISO/IEC 9899:2018):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.7.2.1 Structure and union specifiers (p: 81-84)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-11">
|
|
<ul>
|
|
<li>C11 标准(ISO/IEC 9899:2011):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.7.2.1 Structure and union specifiers (p: 112-117)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-c99">
|
|
<ul>
|
|
<li>C99 标准(ISO/IEC 9899:1999):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.7.2.1 Structure and union specifiers (p: 101-104)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-c89">
|
|
<ul>
|
|
<li>C89/C90 标准(ISO/IEC 9899:1990):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>3.5.2.1 Structure and union specifiers</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<table class="t-dsc-begin"></table>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|