238 lines
18 KiB
HTML
238 lines
18 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_preprocessor_impl 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-preprocessor.html">preprocessor</a></span></div>
|
|
<div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr" xml:lang="zh">
|
|
<p>由 <code>#pragma</code> 指令控制实现定义行为。</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>#pragma</b></code> <span class="t-spar">语用形参</span></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>_Pragma</b></code> <code><b>(</b></code> <span class="t-spar">字符串字面量</span> <code><b>)</b></code></td>
|
|
<td>(2)</td>
|
|
<td><span class="t-mark-rev t-since-c99">(C99 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">1)</span> 以实现定义方式行动(除非 <span class="t-spar">语用形参</span> 是后述的标准 pragma 之一)。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 移除 <span class="t-spar">字符串字面量</span> 的编码前缀(若存在)、外层引号,及开头/尾随空白符,将每个 <code>\"</code> 以 <code>"</code> ,每个 <code>\\</code> 以 <code>\</code> 替换,然后记号化结果(如<a href="c-language-translation_phases.html">翻译阶段 3</a> 中),再如同在 <span class="t-v">(1)</span> 中输出到 <code>#pragma</code> 一般使用结果。</div>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<p>pragma 指令控制编译器的实现指定行为,如禁用编译器警告或更改对齐要求。忽略任何不被识别的 pragma 。</p>
|
|
<h3><span class="mw-headline" id=".E6.A0.87.E5.87.86_pragma">标准 pragma</span></h3>
|
|
<p>语言标准定义下列三个 pragma :</p>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>#pragma STDC FENV_ACCESS</b></code> <span class="t-spar">实参</span></td>
|
|
<td>(1)</td>
|
|
<td><span class="t-mark-rev t-since-c99">(C99 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>#pragma STDC FP_CONTRACT</b></code> <span class="t-spar">实参</span></td>
|
|
<td>(2)</td>
|
|
<td><span class="t-mark-rev t-since-c99">(C99 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>#pragma STDC CX_LIMITED_RANGE</b></code> <span class="t-spar">实参</span></td>
|
|
<td>(3)</td>
|
|
<td><span class="t-mark-rev t-since-c99">(C99 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<p>其中 <span class="t-spar">实参</span> 是 <code><b>ON</b></code> 、 <code><b>OFF</b></code> 和 <code><b>DEFAULT</b></code> 之一。</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 若设为 <code><b>ON</b></code> ,则告知编译器程序将访问或修改<a href="c-numeric-fenv.html">浮点环境</a>,这意味着禁用可能推翻标志测试和模式更改(例如,全局共用子表达式删除、代码移动,及常量折叠)的优化。默认值为实现定义,通常是 <code><b>OFF</b></code> 。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 允许<i>缩略</i>浮点表达式,即忽略舍入错误和浮点异常的优化,被观察成表达式以如同书写方式准确求值。例如,允许 <span class="t-c"><span class="mw-geshi c source-c"><span class="br0">(</span>x<span class="sy2">*</span>y<span class="br0">)</span> <span class="sy2">+</span> z</span></span> 的实现使用单条融合乘加CPU指令。默认值为实现定义,通常是 <code><b>ON</b></code> 。</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 告知编译器复数的乘法、除法,及绝对值可以用简化的数学公式 <span class="texhtml" style="white-space: nowrap;">(x+iy)×(u+iv) = (xu-yv)+i(yu+xv)</span> 、 <span class="texhtml" style="white-space: nowrap;">(x+iy)/(u+iv) = [(xu+yv)+i(yu-xv)]/(u<span class="t-su">2<br /></span>+v<span class="t-su">2<br /></span>)</span> ,及 <span class="texhtml" style="white-space: nowrap;">|x+iy| = <span class="t-mrad"><span>√</span><span>x<span class="t-su">2<br /></span>+y<span class="t-su">2<br /></span></span></span></span> ,不考虑中间溢出的可能性。换言之,程序员保证传递给这些函数的值范围是受限的。默认值为 <code><b>OFF</b></code> 。</div>
|
|
<p>注意:不支持这些 pragma 的编译器可能提供等价的编译时选项,例如 gcc 的 <code>-fcx-limited-range</code> 和 <code>-ffp-contract</code> 。</p>
|
|
<h3><span class="mw-headline" id=".E9.9D.9E.E6.A0.87.E5.87.86_pragma">非标准 pragma</span></h3>
|
|
<h4><span class="mw-headline" id=".23pragma_once">#pragma once</span></h4>
|
|
<p><span class="t-c"><span class="mw-geshi c source-c"><span class="co2">#pragma once</span></span></span> 是受到<a href="https://en.wikipedia.org/wiki/Pragma_once#Portability" class="extiw" title="enwiki:Pragma once">绝大多数现代编译器</a>支持的非标准语用。当某个头文件中包含它时,指示编译器只对其分析一次,即使它在同一源文件中(直接或间接)被包含了多次也是如此。</p>
|
|
<p>阻止同一头文件的多次包含的标准方式是使用<a href="https://en.wikipedia.org/wiki/Include_guard" class="extiw" title="enwiki:Include guard">包含防护</a>:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="co2">#ifndef LIBRARY_FILENAME_H</span>
|
|
<span class="co2">#define LIBRARY_FILENAME_H</span>
|
|
<span class="co1">// 头文件的内容</span>
|
|
<span class="co2">#endif /* LIBRARY_FILENAME_H */</span></pre></div>
|
|
</div>
|
|
<p>从而在任何翻译单元中,该头文件除首次以外被包含时都被排除出编译。所有现代编译器都记录头文件使用了包含防护的事实,只要该防护仍有定义,再遇到该头文件时就不再分析它。(例子见 <a rel="nofollow" class="external text" href="https://gcc.gnu.org/onlinedocs/cpp/Once-Only-Headers.html">gcc</a> )</p>
|
|
<p>使用 <span class="t-c"><span class="mw-geshi c source-c"><span class="co2">#pragma once</span></span></span> 时,同一个头文件可以变为</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="co2">#pragma once</span>
|
|
<span class="co1">// 头文件的内容</span></pre></div>
|
|
</div>
|
|
<p>不同于头文件防护,这条语用使得错误地在多个文件中使用相同的宏名变得不可能。另一方面,因为带 <span class="t-c"><span class="mw-geshi c source-c"><span class="co2">#pragma once</span></span></span> 的文件是基于其文件系统层次的身份所排除的,所以若头文件在项目中有多个位置,则这不能防止包含它两次。</p>
|
|
<h4><span class="mw-headline" id=".23pragma_pack">#pragma pack</span></h4>
|
|
<p>此 pragma 族控制后继定义的结构体和联合体的最大对齐。</p>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>#pragma pack(<span class="t-spar">实参</span>)</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>#pragma pack()</b></code></td>
|
|
<td>(2)</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>#pragma pack(push)</b></code></td>
|
|
<td>(3)</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>#pragma pack(push, <span class="t-spar">实参</span>)</b></code></td>
|
|
<td>(4)</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>#pragma pack(pop)</b></code></td>
|
|
<td>(5)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<p>其中 <span class="t-spar">arg</span> 实参是小的 2 的幂,指定以字节计的新对齐。</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 设置当前对齐为值 <span class="t-spar">实参</span> 。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 设置当前对齐为默认值(由命令行选项指定)。</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 推入当前对齐的值到内部栈。</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 推入当前对齐的值到内部栈然后设置当前对齐为值 <span class="t-spar">实参</span> 。</div>
|
|
<div class="t-li1"><span class="t-li">5)</span> 从内部栈弹出顶条目然后设置(恢复)当前对齐为该值。</div>
|
|
<p><span class="t-c"><span class="mw-geshi c source-c"><span class="co2">#pragma pack</span></span></span> 可以指定结构体的对齐,然而它不能使结构体过对齐。</p>
|
|
<p>参阅 <a rel="nofollow" class="external text" href="https://gcc.gnu.org/onlinedocs/gcc/Structure-Layout-Pragmas.html">GCC</a> 与 <a rel="nofollow" class="external text" href="https://docs.microsoft.com/en-us/cpp/preprocessor/pack">MSVC</a> 的特定细节。</p>
|
|
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style="">
|
|
<tr>
|
|
<td class="mbox-empty-cell"></td>
|
|
<td class="mbox-text" style="">本节未完成<br />
|
|
原因:解释此语用在数据成员的效果还有使用它们的优势与劣势。参考源:
|
|
<ul>
|
|
<li><a rel="nofollow" class="external text" href="https://stackoverflow.com/questions/3318410/pragma-pack-effect">Stack Overflow</a></li>
|
|
</ul>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style="">
|
|
<tr>
|
|
<td class="mbox-empty-cell"></td>
|
|
<td class="mbox-text" style="">本节未完成<br />
|
|
原因:暂无示例</td>
|
|
</tr>
|
|
</table>
|
|
<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.10.9 Pragma operator (p: 129)</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.10.9 Pragma operator (p: 178)</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.10.6 Pragma directive (p: 159)</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.8.6 Pragma directive</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>
|
|
<h3><span class="mw-headline" id=".E5.A4.96.E9.83.A8.E9.93.BE.E6.8E.A5">外部链接</span></h3>
|
|
<ul>
|
|
<li><a rel="nofollow" class="external text" href="https://docs.microsoft.com/en-us/cpp/preprocessor/pragma-directives-and-the-pragma-keyword?view=vs-2019">Visual Studio 2019 的 C++ pragma</a></li>
|
|
<li>GCC 接受的 <a rel="nofollow" class="external text" href="https://gcc.gnu.org/onlinedocs/gcc/Pragmas.html">Pragma</a></li>
|
|
<li>IBM AIX XL C 16.1 的<a rel="nofollow" class="external text" href="https://www.ibm.com/support/knowledgecenter/en/SSGH3R_16.1.0/com.ibm.xlcpp161.aix.doc/compiler_ref/pragma_descriptions.html">单独 pragma 描述</a>及<a rel="nofollow" class="external text" href="https://www.ibm.com/support/knowledgecenter/en/SSGH3R_16.1.0/com.ibm.xlcpp161.aix.doc/language_ref/std_pragmas.html">标准 pragma</a></li>
|
|
<li>Sun Studio 11 C++ 用户手册的 <a rel="nofollow" class="external text" href="http://download.oracle.com/docs/cd/E19422-01/819-3690/Pragmas_App.html#73499">Appendix B. Pragmas</a></li>
|
|
<li><a rel="nofollow" class="external text" href="https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/pragmas.html">Intel C++ compiler pragmas</a></li>
|
|
<li><a rel="nofollow" class="external text" href="http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/Online_Help/pragmas.htm">HP aCC compiler pragmas</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|