198 lines
22 KiB
HTML
198 lines
22 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>volatile 类型限定符</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_volatile skin-cppreference2 action-view cpp-navbar">
|
|
<div id="cpp-content-base">
|
|
<div id="content"><a id="top"></a>
|
|
<h1 id="firstHeading" class="firstHeading">volatile 类型限定符</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>C <a href="c-language-type.html" class="mw-redirect">类型系统</a>中每一个独立的类型在都有数个该类型的<i>限定</i>版本,对应 <a href="c-language-const.html">const</a> 、 <i>volatile</i> 及对于指向对象指针的 <a href="c-language-restrict.html">restrict</a> 限定符中的一个、两个或全部三个。此页面描述 <i>volatile</i> 限定符的效果。</p>
|
|
<p>每一个通过对 volatile 限定类型左值表达式的访问(读与写),对于优化意图都被认为是可观副效应,从而访问会严格按照抽象机的规则求值(即所有写入会在下一个序点之前的某时完成)。这表明在执行的单个线程内,volatile 访问不能被优化掉,亦不能与另一个被<a href="c-language-eval_order.html">顺序点</a>分隔了 volatile 访问的可观副效应重排。</p>
|
|
<p>一个非 volatile 值到 volatile 值的转换是无效果的。欲使用 volatile 语义访问非 volatile 对象,必须先将其地址转换成指向 volatile 类型的指针,再通过该指针访问该对象。</p>
|
|
<p>任何通过非 volatile 左值结果,对拥有 volatile 限定类型的对象尝试读或写会导致未定义行为:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">volatile</span> <span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// volatile 限定类型</span>
|
|
<span class="kw4">int</span><span class="sy2">*</span> p <span class="sy1">=</span> <span class="br0">(</span><span class="kw4">int</span><span class="sy2">*</span><span class="br0">)</span><span class="sy3">&</span>n<span class="sy4">;</span>
|
|
<span class="kw4">int</span> val <span class="sy1">=</span> <span class="sy2">*</span>p<span class="sy4">;</span> <span class="co1">// 未定义行为</span></pre></div>
|
|
</div>
|
|
<p>volatile 限定的结构体或联合体类型,其成员会获取其所属类型的限定(当通过 <code><b>.</b></code> 或 <code><b>-></b></code> 运算符时):</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw1">struct</span> s <span class="br0">{</span> <span class="kw4">int</span> i<span class="sy4">;</span> <span class="kw4">const</span> <span class="kw4">int</span> ci<span class="sy4">;</span> <span class="br0">}</span> s<span class="sy4">;</span>
|
|
<span class="co1">// s.i 类型是 int,s.ci 的类型是 const int</span>
|
|
<span class="kw4">volatile</span> <span class="kw1">struct</span> s vs<span class="sy4">;</span>
|
|
<span class="co1">// vs.i 和 vs.ci 的类型各是 volatile int 和 const volatile int</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-c23">
|
|
<td>
|
|
<p>若以 volatile 类型限定符声明数组类型(通过使用 <a href="c-language-typedef.html">typedef</a> ),则数组类型无 volatile 限定,但其元素类型有。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-c23">(C23 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-c23">
|
|
<td>
|
|
<p>始终认为数组类型与其元素类型同等地拥有 volatile 限定。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c23">(C23 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>若函数类型声明具有 volatile 类型限定(通过使用 <a href="c-language-typedef.html">typedef</a> ),则行为未定义。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw1">typedef</span> <span class="kw4">int</span> A<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span><span class="sy4">;</span>
|
|
<span class="kw4">volatile</span> A a <span class="sy1">=</span> <span class="br0">{</span><span class="br0">{</span><span class="nu0">4</span>, <span class="nu0">5</span>, <span class="nu0">6</span><span class="br0">}</span>, <span class="br0">{</span><span class="nu0">7</span>, <span class="nu0">8</span>, <span class="nu0">9</span><span class="br0">}</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// volatile int 的数组的数组</span>
|
|
<span class="kw4">int</span><span class="sy2">*</span> pi <span class="sy1">=</span> a<span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 错误:a[0] 拥有 volatile int* 类型</span>
|
|
<span class="kw4">void</span> <span class="sy2">*</span>unqual_ptr <span class="sy1">=</span> a<span class="sy4">;</span> <span class="co1">// C23 前 OK ; C23 起错误</span>
|
|
<span class="co1">// 注: clang 即使在 C89-C17 模式也应用 C++/C23 中的规则</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c99">
|
|
<td>
|
|
<p>在函数声明中,关键词 <code>volatile</code> 可以出现于方括号内,用以声明函数参数的数组类型。它对数组所转换得的指针类型赋予限定。</p>
|
|
<p>下列两个声明声明同一函数:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">double</span> x<span class="br0">[</span><span class="kw4">volatile</span><span class="br0">]</span>, <span class="kw4">const</span> <span class="kw4">double</span> y<span class="br0">[</span><span class="kw4">volatile</span><span class="br0">]</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">double</span> <span class="sy2">*</span> <span class="kw4">volatile</span> x, <span class="kw4">const</span> <span class="kw4">double</span> <span class="sy2">*</span> <span class="kw4">volatile</span> y<span class="br0">)</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c99">(C99 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>指向非 volatile 类型的指针可以隐式转换成指向同一或<a href="c-language-types.html#.E5.85.BC.E5.AE.B9.E7.B1.BB.E5.9E.8B">兼容类型</a>的 volatile 限定版本的指针。逆向转换可以由类型转换表达式进行。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">int</span><span class="sy2">*</span> p <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span>
|
|
<span class="kw4">volatile</span> <span class="kw4">int</span><span class="sy2">*</span> vp <span class="sy1">=</span> p<span class="sy4">;</span> <span class="co1">// OK:添加限定符( int 到 volatile int)</span>
|
|
p <span class="sy1">=</span> vp<span class="sy4">;</span> <span class="co1">// 错误:丢弃限定符( volatile int 到 int)</span>
|
|
p <span class="sy1">=</span> <span class="br0">(</span><span class="kw4">int</span><span class="sy2">*</span><span class="br0">)</span>vp<span class="sy4">;</span> <span class="co1">// OK:类型转换</span></pre></div>
|
|
</div>
|
|
<p>注意指向<code>T</code>的二重不可转换成指向<code>volatile T</code>的二重指针;对于要兼容的两个类型,它们的限定必须相同:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">char</span> <span class="sy2">*</span>p <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span>
|
|
<span class="kw4">volatile</span> <span class="kw4">char</span> <span class="sy2">**</span>vpp <span class="sy1">=</span> <span class="sy3">&</span>p<span class="sy4">;</span> <span class="co1">// 错误: char* 和 volatile char* 不是兼容类型</span>
|
|
<span class="kw4">char</span> <span class="sy2">*</span> <span class="kw4">volatile</span> <span class="sy2">*</span>pvp <span class="sy1">=</span> <span class="sy3">&</span>p<span class="sy4">;</span> <span class="co1">// OK,添加限定符( char* 到 char* volatile )</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id="volatile_.E7.9A.84.E7.94.A8.E6.B3.95"><code>volatile</code> 的用法</span></h3>
|
|
<div class="t-li1"><span class="t-li">1)</span> <a href="c-language-storage_duration.html">static</a> <code>volatile</code> 对象模仿映射于内存的 I/O 端口,而 <code>static</code> <code>const</code> <code>volatile</code> 对象模仿映射于内存的输入端口,例如实时时钟:
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">volatile</span> <span class="kw4">short</span> <span class="sy2">*</span>ttyport <span class="sy1">=</span> <span class="br0">(</span><span class="kw4">volatile</span> <span class="kw4">short</span><span class="sy2">*</span><span class="br0">)</span>TTYPORT_ADDR<span class="sy4">;</span>
|
|
<span class="kw1">for</span><span class="br0">(</span><span class="kw4">int</span> i <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> i <span class="sy1"><</span> N<span class="sy4">;</span> <span class="sy2">++</span>i<span class="br0">)</span>
|
|
<span class="sy2">*</span>ttyport <span class="sy1">=</span> a<span class="br0">[</span>i<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// *ttyport 是 volatile short 类型的左值</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> <span class="t-lc"><a href="c-program-sig_atomic_t.html">sig_atomic_t</a></span> 类型的 <code>static</code> <code>volatile</code> 对象用于与 <span class="t-lc"><a href="c-program-signal.html">signal</a></span> 处理交流。</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 含有对 <span class="t-lc"><a href="c-program-setjmp.html">setjmp</a></span> 宏调用的函数中的局部 <code>volatile</code> 变量,是在 <span class="t-lc"><a href="c-program-longjmp.html">longjmp</a></span> 返回后仅有保证恢复其值的局部变量。</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 另外,volatile 变量可用于禁用某些优化形式,例如禁用死存储消除,或为微基准禁用常量折叠。</div>
|
|
<p>注意 volatile 变量不适合线程间交流;它们不提供原子性、同步或内存顺序。读取一个被另一线程未经同步地修改的 volatile 变量,或两个未同步的线程的共时修改,对于一些数据竞争是未定义行为。</p>
|
|
<h3><span class="mw-headline" id=".E5.85.B3.E9.94.AE.E8.AF.8D">关键词</span></h3>
|
|
<p><a href="c-keyword-volatile.html"><tt>volatile</tt></a></p>
|
|
<h3><span class="mw-headline" id=".E7.A4.BA.E4.BE.8B">示例</span></h3>
|
|
<div class="t-example">
|
|
<p>展示用 volatile 禁用优化</p>
|
|
<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 <time.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>
|
|
<a href="c-chrono-clock_t.html"><span class="kw525">clock_t</span></a> t <span class="sy1">=</span> <a href="c-chrono-clock.html"><span class="kw514">clock</span></a><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">double</span> d <span class="sy1">=</span> <span class="nu16">0.0</span><span class="sy4">;</span>
|
|
<span class="kw1">for</span> <span class="br0">(</span><span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> n <span class="sy1"><</span> <span class="nu0">10000</span><span class="sy4">;</span> <span class="sy2">++</span>n<span class="br0">)</span>
|
|
<span class="kw1">for</span> <span class="br0">(</span><span class="kw4">int</span> m <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> m <span class="sy1"><</span> <span class="nu0">10000</span><span class="sy4">;</span> <span class="sy2">++</span>m<span class="br0">)</span>
|
|
d <span class="sy2">+</span><span class="sy1">=</span> d <span class="sy2">*</span> n <span class="sy2">*</span> m<span class="sy4">;</span> <span class="co1">// 读写非 volatile 对象</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"Modified a non-volatile variable 100m times. "</span>
|
|
<span class="st0">"Time used: %.2f seconds<span class="es1">\n</span>"</span>,
|
|
<span class="br0">(</span><span class="kw4">double</span><span class="br0">)</span><span class="br0">(</span><a href="c-chrono-clock.html"><span class="kw514">clock</span></a><span class="br0">(</span><span class="br0">)</span> <span class="sy2">-</span> t<span class="br0">)</span><span class="sy2">/</span><a href="c-chrono-CLOCKS_PER_SEC.html"><span class="kw522">CLOCKS_PER_SEC</span></a><span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
t <span class="sy1">=</span> <a href="c-chrono-clock.html"><span class="kw514">clock</span></a><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">volatile</span> <span class="kw4">double</span> vd <span class="sy1">=</span> <span class="nu16">0.0</span><span class="sy4">;</span>
|
|
<span class="kw1">for</span> <span class="br0">(</span><span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> n <span class="sy1"><</span> <span class="nu0">10000</span><span class="sy4">;</span> <span class="sy2">++</span>n<span class="br0">)</span>
|
|
<span class="kw1">for</span> <span class="br0">(</span><span class="kw4">int</span> m <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> m <span class="sy1"><</span> <span class="nu0">10000</span><span class="sy4">;</span> <span class="sy2">++</span>m<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw4">double</span> prod <span class="sy1">=</span> vd <span class="sy2">*</span> n <span class="sy2">*</span> m<span class="sy4">;</span> <span class="co1">// 读 volatile 对象</span>
|
|
vd <span class="sy2">+</span><span class="sy1">=</span> prod<span class="sy4">;</span> <span class="co1">// 读写 volatile 对象</span>
|
|
<span class="br0">}</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"Modified a volatile variable 100m times. "</span>
|
|
<span class="st0">"Time used: %.2f seconds<span class="es1">\n</span>"</span>,
|
|
<span class="br0">(</span><span class="kw4">double</span><span class="br0">)</span><span class="br0">(</span><a href="c-chrono-clock.html"><span class="kw514">clock</span></a><span class="br0">(</span><span class="br0">)</span> <span class="sy2">-</span> t<span class="br0">)</span><span class="sy2">/</span><a href="c-chrono-CLOCKS_PER_SEC.html"><span class="kw522">CLOCKS_PER_SEC</span></a><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">Modified a non-volatile variable 100m times. Time used: 0.00 seconds
|
|
Modified a volatile variable 100m times. Time used: 0.79 seconds</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.3 Type qualifiers (p: 87-90)</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.3 Type qualifiers (p: 121-123)</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.3 Type qualifiers (p: 108-110)</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>6.5.3 Type qualifiers</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>
|