191 lines
18 KiB
HTML
191 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-cpp_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="cpp.html">cpp</a>‎ | <a href="cpp-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-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">1)</span> 具有由实现定义的行为方式</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 从 <span class="t-spar">字符串字面量</span> 移除 <code>L</code> 前缀(若存在),外层引号,及前导/尾随空白符,将每个 <code>\"</code> 替换为 <code>"</code>、将每个 <code>\\</code> 替换为 <code>\</code>,然后将结果记号化(如<a href="cpp-language-translation_phases.html">翻译阶段 3</a> 中一样),再如同将结果作为 <span class="t-v">(1)</span> 中的输入来予以使用。</div>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<p>pragma 指令控制编译器的特定于实现的行为,如禁用编译器警告或更改对齐要求。无法识别的语用会被忽略。</p>
|
|
<h3><span class="mw-headline" id=".E9.9D.9E.E6.A0.87.E5.87.86.E8.AF.AD.E7.94.A8">非标准语用</span></h3>
|
|
<p>ISO C++ 语言标准并不要求编译器支持任何语用。不过,多种实现都支持几种非标准的语用:</p>
|
|
<h4><span class="mw-headline" id=".23pragma_STDC">#pragma STDC</span></h4>
|
|
<p>ISO C 语言标准要求 C 编译器支持下列三种语用,一些 C++ 编译器供应商在它们的 C++ 前端中以不同的程度支持它们:</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 class="t-sdsc-nopad"></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 class="t-sdsc-nopad"></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 class="t-sdsc-nopad"></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>缩略(contracting)</i>行为,即一种优化,表达式严格按书面求值时可被观察到的一些舍入错误和浮点异常将被忽略。例如,允许 <span class="t-c"><span class="mw-geshi cpp source-cpp"><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>如果上述三种语用的任一条并非出现于所有外部声明之外,或所有显式声明或复合语句中的所有语句之前,则程序的行为未定义。</p>
|
|
<p>注意:不支持这些 pragma 的编译器可能提供等价的编译时选项,例如 gcc 的 <code>-fcx-limited-range</code> 和 <code>-ffp-contract</code>。</p>
|
|
<h4><span class="mw-headline" id=".23pragma_once">#pragma once</span></h4>
|
|
<p><span class="t-c"><span class="mw-geshi cpp source-cpp"><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="cpp source-cpp">
|
|
<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 cpp source-cpp"><span class="co2">#pragma once</span></span></span> 时,同一个头文件可以变为</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<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 cpp source-cpp"><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 cpp source-cpp"><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.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>HP aCC A.06.25 的<a rel="nofollow" class="external text" href="http://h20565.www2.hpe.com/hpsc/doc/public/display?sp4ts.oid=4268164&docLocale=en_US&docId=emr_na-c02653979">发行注记(包括 pragma)</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|