297 lines
28 KiB
HTML
297 lines
28 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_storage_duration 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>指定对象和函数的<i>存储期( storage duration )</i>和<i>链接( linkage )</i>:</p>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li><code><b>auto</b></code> - 自动存储期与无链接</li>
|
|
<li><code><b>register</b></code> - 自动存储期与无链接;不能取这种对象的地址</li>
|
|
<li><code><b>static</b></code> - 静态存储期与内部链接(除非在块作用域)</li>
|
|
<li><code><b>extern</b></code> - 静态存储期与外部链接(除非已声明带内部链接)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c11">
|
|
<td>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li><code><b>_Thread_local</b></code> - 线程存储期</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c11">(C11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<p>存储类说明符出现于<a href="c-language-declarations.html">声明</a>中。至多可使用一个说明符<span class="t-rev-inl t-since-c11"><span>,除了能将 <code>_Thread_local</code> 与 <code>static</code> 或 <code>extern</code> 组合以调整链接</span> <span><span class="t-mark-rev t-since-c11">(C11 起)</span></span></span>。存储类说明符确定其所声明的名称的二个独立属性:<i>存储期</i>与<i>链接</i>。</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> <code>auto</code> 说明符只对声明于块作用域的对象(除了函数参数列表)允许。它指示自动存储期与无链接,也是这种声明的默认属性。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> <code>register</code> 说明符只对声明于块作用域的对象允许,包括函数参数列表。它指示自动存储期与无链接(即这种声明的默认属性),但另外提示优化器,若可能则将此对象的值存储于 CPU 寄存器中。无论此优化是否发生,声明为 <code>register</code> 的对象不能用作<a href="c-language-operator_member_access.html">取址运算符</a>的参数<span class="t-rev-inl t-since-c11"><span>,不能用 <a href="c-language-_Alignas.html">_Alignas</a></span> <span><span class="t-mark-rev t-since-c11">(C11 起)</span></span></span>,而且 <code>register</code> 数组不能转换为指针。</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> <code>static</code> 说明符指定静态存储期<span class="t-rev-inl t-since-c11"><span>(除非与 <code>_Thread_local</code> 组合)</span> <span><span class="t-mark-rev t-since-c11">(C11 起)</span></span></span>和内部链接(除非用于块作用域)。它能用于在文件作用域的函数,以及文件和块作用域的对象,但不能用于函数参数列表。</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> <code>extern</code> 指定静态存储期<span class="t-rev-inl t-since-c11"><span>(除非与 <code>_Thread_local</code> 组合)</span> <span><span class="t-mark-rev t-since-c11">(C11 起)</span></span></span>和外部链接。它能用于文件和块作用域中的函数和对象声明(除了函数参数列表)。若 <code>extern</code> 出现在已经声明带内部链接的标识符的再声明上,则链接仍为内部。否则(若前一声明为外部、无链接或不在作用域内)链接为外部。</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c11">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">5)</span> <code>_Thread_local</code> 指示<i>线程存储期</i>。它不能用于函数声明。若将它用在对象声明上,则它必须在同一对象的每次声明上都存在。若将它用在块作用域声明上,则必须与 <code>static</code> 或 <code>extern</code> 之一组合以决定链接。</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c11">(C11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>若不提供存储类说明符,则默认为:</p>
|
|
<dl>
|
|
<dd>对所有函数为 <code>extern</code></dd>
|
|
<dd>对在文件作用域的对象为 <code>extern</code></dd>
|
|
<dd>对在块作用域的对象为 <code>auto</code></dd>
|
|
</dl>
|
|
<p>对于任何用存储类说明符声明的结构体或联合体,存储期(但非链接)递归地应用到其成员。</p>
|
|
<p>在块作用域的函数声明能使用 <code>extern</code> 或完全不使用存储类说明符。在文件作用域的函数声明能使用 <code>extern</code> 或 <code>static</code> 。</p>
|
|
<p>函数参数不能使用异于 <code>register</code> 的存储类说明符。注意 <code>static</code> 在数组类型的函数参数中有特殊含义。</p>
|
|
<h3><span class="mw-headline" id=".E5.AD.98.E5.82.A8.E6.9C.9F">存储期</span></h3>
|
|
<p>每个<a href="c-language-object.html">对象</a>都有称为<i>存储期</i>的属性,它限制对象的<a href="c-language-lifetime.html">生存期</a>。 C 中有四种存储期:</p>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li><i><b>自动</b></i>存储期。进入声明对象于其中的<a href="c-language-statements.html#.E5.A4.8D.E5.90.88.E8.AF.AD.E5.8F.A5">块</a>时分配其存储,而在以任何方式( <a href="c-language-goto.html">goto</a> 、 <a href="c-language-return.html">return</a> 、抵达结尾)退出该块时解分配存储。<span class="t-rev-inl t-since-c99"><span>一个例外是 <a href="c-language-array.html#.E5.8F.98.E9.95.BF.E5.BA.A6.E6.95.B0.E7.BB.84">VLA</a> ;在执行声明时而非块入口分配其存储,并在声明离开作用域而非退出块时解分配存储。</span> <span><span class="t-mark-rev t-since-c99">(C99 起)</span></span></span>若递归地进入块,则对每个递归层进行新的分配。所有函数参数和非 <code>static</code> 块作用域对象,还有用于块作用域的<a href="c-language-compound_literal.html">复合字面量</a>拥有此存储期。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li><i><b>静态</b></i>存储期。存储期是整个程序的执行过程,只在 <a href="c-language-main_function.html"><code>main</code> 函数</a>之前初始化一次存储于对象的值。所有声明为 <code>static</code> 对象和所有带内部或外部链接<span class="t-rev-inl t-since-c11"><span>且不声明为 <code>_Thread_local</code></span> <span><span class="t-mark-rev t-since-c11">(C11 起)</span></span></span>的对象都拥有此存储期。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c11">
|
|
<td>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li><i><b>线程</b></i>存储期。存储期是创建对象的线程的整个执行过程,在启动线程时初始化存储于对象的值。每个线程拥有其自身的相异对象。若执行访问此对象的表达式的线程,不是执行其初始化的线程,则行为是实现定义的。所有声明为 <code>_Thread_local</code> 的对象拥有此存储期。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c11">(C11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li><i><b>分配</b></i>存储期。按照请求,用<a href="c-memory.html">动态内存分配</a>函数分配和解分配存储。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<h4><span class="mw-headline" id=".E9.93.BE.E6.8E.A5">链接</span></h4>
|
|
<p>链接指的是在其他作用域指代一个标识符(具名对象或函数)的能力。若在数个作用域中声明有同一标识符的对象或函数,但不能从所有这些作用域指代它们,则会创建数个对象的实例。辨识下列链接:</p>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li><i><b>无链接</b></i>。只能从其所在的作用域指代该标识符。所有函数参数和所有非 <code>extern</code> 的块作用域对象(包含声明为 <code>static</code> 者)拥有此链接。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li><i><b>内部链接</b></i>。能从当前翻译单元的所有作用域指代该标识符。所有 <code>static</code> 文件作用域标识符(函数和对象)都拥有此链接。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li><i><b>外部链接</b></i>。能从整个程序的任何其他翻译单元指代该标识符。所有非 <code>static</code> 函数、所有 <code>extern</code> 对象(除非之前声明为 <code>static</code> )和所有文件作用域的非 <code>static</code> 对象拥有此链接。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<p>若同一标识符在同一翻译单元中一同带内部和外部链接出现,则行为未定义。这在使用<a href="c-language-extern.html">试探性定义</a>时有可能。</p>
|
|
<h4><span class="mw-headline" id=".E9.93.BE.E6.8E.A5.E4.B8.8E.E5.BA.93">链接与库</span></h4>
|
|
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style="">
|
|
<tr>
|
|
<td class="mbox-empty-cell"></td>
|
|
<td class="mbox-text" style="">本节未完成<br />
|
|
原因:这或许应该为 <a href="c-language.html">c/language</a> 中<b>杂项</b>下的顶层条目?</td>
|
|
</tr>
|
|
</table>
|
|
<p>带外部链接的声明常在头文件中可用,这使得所有 <a href="c-preprocessor-include.html">#include</a> 该头文件的翻译单元都可以指代定义于别处的相同标识符。</p>
|
|
<p>任何出现于头文件中的带内部链接的声明,在每个包含该文件的翻译单元中产生一个分离而相异的对象或函数。</p>
|
|
<p>库接口:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="co1">// flib.h</span>
|
|
<span class="co2">#ifndef FLIB_H</span>
|
|
<span class="co2">#define FLIB_H</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 带外部链接的函数声明</span>
|
|
<span class="kw2">extern</span> <span class="kw4">int</span> state<span class="sy4">;</span> <span class="co1">// 带外部链接的对象声明</span>
|
|
<span class="kw4">static</span> <span class="kw4">const</span> <span class="kw4">int</span> size <span class="sy1">=</span> <span class="nu0">5</span><span class="sy4">;</span> <span class="co1">// 带内部链接的只读对象定义</span>
|
|
<span class="kw2">enum</span> <span class="br0">{</span> MAX <span class="sy1">=</span> <span class="nu0">10</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 常量定义</span>
|
|
<span class="kw1">inline</span> <span class="kw4">int</span> sum <span class="br0">(</span><span class="kw4">int</span> a, <span class="kw4">int</span> b<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> a<span class="sy2">+</span>b<span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// inline 函数定义</span>
|
|
<span class="co2">#endif // FLIB_H</span></pre></div>
|
|
</div>
|
|
<p>库实现:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="co1">// flib.c</span>
|
|
<span class="co2">#include "flib.h"</span>
|
|
<span class="kw4">static</span> <span class="kw4">void</span> local_f<span class="br0">(</span><span class="kw4">int</span> s<span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="co1">// 带内部链接的定义(只用于此文件)</span>
|
|
<span class="kw4">static</span> <span class="kw4">int</span> local_state<span class="sy4">;</span> <span class="co1">// 带内部链接的定义(只用于此文件)</span>
|
|
|
|
<span class="kw4">int</span> state<span class="sy4">;</span> <span class="co1">// 带外部链接的定义( main.c 使用)</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span> <span class="br0">{</span>local_f<span class="br0">(</span>state<span class="br0">)</span><span class="sy4">;</span><span class="br0">}</span> <span class="co1">// 带外部链接的定义( main.c 使用)</span></pre></div>
|
|
</div>
|
|
<p>应用代码:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="co1">// main.c </span>
|
|
<span class="co2">#include "flib.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="kw4">int</span> x<span class="br0">[</span>MAX<span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span>size<span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 使用常量和只读变量</span>
|
|
state <span class="sy1">=</span> <span class="nu0">7</span><span class="sy4">;</span> <span class="co1">// 修改 flib.c 中的 state</span>
|
|
f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 flib.c 中的 f()</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.85.B3.E9.94.AE.E8.AF.8D">关键词</span></h3>
|
|
<p><a href="c-keyword-auto.html"><tt>auto</tt></a>, <a href="c-keyword-register.html"><tt>register</tt></a>, <a href="c-keyword-static.html"><tt>static</tt></a>, <a href="c-keyword-extern.html"><tt>extern</tt></a>, <a href="c-keyword-_Thread_local.html"><tt>_Thread_local</tt></a></p>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<p>一般通过定义于头文件 <code>threads.h</code> 的便利宏 <span class="t-lc"><a href="c-thread-thread_local.html">thread_local</a></span> 使用关键词 <code>_Thread_local</code> 。</p>
|
|
<p>C 语言文法中, <a href="c-language-typedef.html"><code>typedef</code></a> 说明符在形式上列作存储类说明符,但它被用于声明类型名,而不指定存储。</p>
|
|
<p>在文件作用域的 <code>const</code> 且非 <code>extern</code> 的名称在 C 中拥有外部链接(同所有文件作用域的默认情况),但在 C++ 中拥有内部链接。</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 <stdlib.h></span>
|
|
|
|
<span class="kw4">int</span> A<span class="sy4">;</span> <span class="co1">// 静态存储期</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"&A = %p<span class="es1">\n</span>"</span>, <span class="br0">(</span><span class="kw4">void</span><span class="sy2">*</span><span class="br0">)</span><span class="sy3">&</span>A<span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 自动存储期</span>
|
|
<span class="kw4">int</span> A <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// 隐藏全局 A</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"&A = %p<span class="es1">\n</span>"</span>, <span class="br0">(</span><span class="kw4">void</span><span class="sy2">*</span><span class="br0">)</span><span class="sy3">&</span>A<span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 分配存储期</span>
|
|
<span class="kw4">int</span> <span class="sy2">*</span>ptr_1 <span class="sy1">=</span> <a href="c-memory-malloc.html"><span class="kw403">malloc</span></a><span class="br0">(</span><span class="kw4">sizeof</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 开始分配存储期</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"address of int in allocated memory = %p<span class="es1">\n</span>"</span>, <span class="br0">(</span><span class="kw4">void</span><span class="sy2">*</span><span class="br0">)</span>ptr_1<span class="br0">)</span><span class="sy4">;</span>
|
|
<a href="c-memory-free.html"><span class="kw406">free</span></a><span class="br0">(</span>ptr_1<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 停止分配存储期</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">&A = 0x600ae4
|
|
&A = 0x7ffefb064f5c
|
|
address of int in allocated memory = 0x1f28c30</pre></div>
|
|
</div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.BC.95.E7.94.A8">引用</span></h3>
|
|
<div class="t-ref-std-11">
|
|
<ul>
|
|
<li>C11 标准(ISO/IEC 9899:2011):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.2.2 Linkages of identifiers (p: 36-37)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.2.4 Storage durations of objects (p: 38-39)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.7.1 Storage-class specifiers (p: 109-110)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<div class="t-ref-std-c99">
|
|
<ul>
|
|
<li>C99 标准(ISO/IEC 9899:1999):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.2.2 Linkages of identifiers (p: 30-31)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.2.4 Storage durations of objects (p: 32)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.7.1 Storage-class specifiers (p: 98-99)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<div class="t-ref-std-c89">
|
|
<ul>
|
|
<li>C89/C90 标准(ISO/IEC 9899:1990):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>3.1.2.2 Linkages of identifiers</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>3.1.2.4 Storage durations of objects</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>3.5.1 Storage-class 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>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|