205 lines
25 KiB
HTML
205 lines
25 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_include 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>将其他源文件包含到当前源文件中紧随指令之后的一行。</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>#include <</b></code> <span class="t-spar">h字符序列</span> <code><b>></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>#include "</b></code> <span class="t-spar">q字符序列</span> <code><b>"</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>#include</b></code> <span class="t-spar">记号序列</span> <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>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>__has_include</b></code> <code><b>(</b></code> <code><b>"</b></code> <span class="t-spar">q字符序列</span> <code><b>"</b></code> <code><b>)</b></code><br />
|
|
<code><b>__has_include</b></code> <code><b>(</b></code> <code><b><</b></code> <span class="t-spar">h字符序列</span> <code><b>></b></code> <code><b>)</b></code></td>
|
|
<td>(4)</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>__has_include</b></code> <code><b>(</b></code> <span class="t-spar">字符串字面量</span> <code><b>)</b></code><br />
|
|
<code><b>__has_include</b></code> <code><b>(</b></code> <code><b><</b></code> <span class="t-spar">h记号序列</span> <code><b>></b></code> <code><b>)</b></code></td>
|
|
<td>(5)</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</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">h字符序列</span> 唯一识别的头,并将该指令替换为这个头的全部内容。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 搜索由 <span class="t-spar">q字符序列</span> 识别的源文件,并将该指令替换为这个源文件的全部内容。可以退回至语法 (1) 并将 <span class="t-spar">q字符序列</span> 视为头标识符。</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 如果 (1) 和 (2) 都不匹配,<span class="t-spar">记号序列</span>会经历宏替换。该指令在替换后会再次尝试匹配 (1) 和 (2)。</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 检查一个头或源文件是否可以被包含。</div>
|
|
<div class="t-li1"><span class="t-li">5)</span> 如果 (4) 不匹配,<span class="t-spar">h记号序列</span>会经历宏替换。T该指令在替换后会再次尝试匹配 (4)。</div>
|
|
<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">h字符序列</span></td>
|
|
<td>-</td>
|
|
<td>一个或多个 <span class="t-spar">h字符</span></td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">h字符</span></td>
|
|
<td>-</td>
|
|
<td><span class="t-rev-inl t-until-cxx23"><span><a href="cpp-language-translation_phases.html#.E9.98.B6.E6.AE.B5_5">源字符集</a></span> <span><span class="t-mark-rev t-until-cxx23">(C++23 前)</span></span></span><span class="t-rev-inl t-since-cxx23"><span><a href="cpp-language-charset.html#.E7.BF.BB.E8.AF.91.E5.AD.97.E7.AC.A6.E9.9B.86">翻译字符集</a></span> <span><span class="t-mark-rev t-since-cxx23">(C++23 起)</span></span></span> 除了换行符和 <code>></code> 以外的任何成员</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">q字符序列</span></td>
|
|
<td>-</td>
|
|
<td>一个或多个 <span class="t-spar">q字符</span></td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">q字符</span></td>
|
|
<td>-</td>
|
|
<td><span class="t-rev-inl t-until-cxx23"><span><a href="cpp-language-translation_phases.html#.E9.98.B6.E6.AE.B5_5">源字符集</a></span> <span><span class="t-mark-rev t-until-cxx23">(C++23 前)</span></span></span><span class="t-rev-inl t-since-cxx23"><span><a href="cpp-language-charset.html#.E7.BF.BB.E8.AF.91.E5.AD.97.E7.AC.A6.E9.9B.86">翻译字符集</a></span> <span><span class="t-mark-rev t-since-cxx23">(C++23 起)</span></span></span> 除了换行符和 <code>"</code> 以外的任何成员</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">记号序列</span></td>
|
|
<td>-</td>
|
|
<td>一个或多个<a href="cpp-language-translation_phases.html#.E9.98.B6.E6.AE.B5_3">预处理记号</a></td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">字符串字面量</span></td>
|
|
<td>-</td>
|
|
<td>一个<a href="cpp-language-string_literal.html">字符串字面量</a></td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">h记号序列</span></td>
|
|
<td>-</td>
|
|
<td>一个或多个除了 <code>></code> 以外的<a href="cpp-language-translation_phases.html#.E9.98.B6.E6.AE.B5_3">预处理记号</a></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E8.AF.B4.E6.98.8E">说明</span></h3>
|
|
<div class="t-li1"><span class="t-li">1)</span> 在一系列由实现定义的地点中搜索由 <span class="t-spar">h字符序列</span> 唯一识别的头,并将该指令替换为这个头的全部内容。由实现定义如何制指定这些地点和识别头。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 将该指令替换为由 <span class="t-spar">q字符序列</span> 识别的源文件的全部内容。命名的源文件通过由实现定义的方式进行搜索。如果不支持这种搜索或者搜索失败,该指令按语法 (1) 重新处理,将原指令中包含的序列(包括大于号,如果存在)作为语法 (1) 中所需的序列。</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 该指令中 <code><b>include</b></code> 后面的预处理记号会按在正常文本中进行处理(即每个目前定义为宏名的标识符都会被替换为它的预处理记号替换列表)如果在所有替换都完成后生成的指令不匹配前面两种语法,那么行为未定义。将在一对预处理记号 < 和 > 之间或一对 " 字符之前的预处理记号序列合并为单个头名预处理记号的方法由实现定义。</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 搜索由 <span class="t-spar">h字符序列</span> 或 <span class="t-spar">q字符序列</span> 识别的头或源文件,如同通过将该预处理记号序列作为语法 (3) 中的 <span class="t-spar">记号序列</span> 的方法进行搜索,但不会有后续的宏展开会执行。如果刚才的语法 (3) 指令不满足 <code>#include</code> 指令的语法要求,那么程序非良构。如果搜索成功,<code>__has_include</code> 表达式求值为 1,否则(搜索失败时)求值为 0。</div>
|
|
<div class="t-li1"><span class="t-li">5)</span> 只有在不匹配 (4) 才会选择此形式,此时预处理记号会按在正常文本中进行处理。</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p>如果由 <span class="t-spar">头名</span>(即 <code><b><</b></code> <span class="t-spar">h字符序列</span> <code><b>></b></code> 或 <code><b>"</b></code> <span class="t-spar">q字符序列</span> <code><b>"</b></code>)标识的头指明了一个可以导入的头,那么由实现决定要包含这个头的 <code>#include</code> 预处理指令是否要被替换为具有以下形式的<a href="cpp-language-modules.html#.E5.AF.BC.E5.85.A5.E6.A8.A1.E5.9D.97.E5.92.8C.E5.A4.B4">导入指令</a>:</p>
|
|
<p><code><b>import</b></code> <span class="t-spar">头名</span> <code><b>;</b></code> <span class="t-spar">换行</span></p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p><code>__has_include</code> 可以在 <a href="cpp-preprocessor-conditional.html"><tt>#if</tt></a> 和 <a href="cpp-preprocessor-conditional.html"><tt>#elif</tt></a> 中的表达式展开。它被 <a href="cpp-preprocessor-conditional.html"><tt>#ifdef</tt></a>, <a href="cpp-preprocessor-conditional.html"><tt>#ifndef</tt></a><span class="t-rev-inl t-since-cxx23"><span>, <a href="cpp-preprocessor-conditional.html"><tt>#elifdef</tt></a>, <a href="cpp-preprocessor-conditional.html"><tt>#elifndef</tt></a></span> <span><span class="t-mark-rev t-since-cxx23">(C++23 起)</span></span></span> 和 <a href="cpp-preprocessor-conditional.html"><tt>defined</tt></a> 视为已定义的宏,但不能在其他任何地方使用。</p>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<p>语法 (1) 的意图是搜索由实现所掌控的文件。典型实现仅搜索标准包含目录。这些标准包含目录中隐含地包含标准 C++ 库和标准 C 库。用户通常能通过编译器选项来控制标准包含目录。</p>
|
|
<p>语法 (2) 的意图是搜索不被实现所掌控的文件。典型实现首先于当前文件所在的目录搜索,然后退回使用语法 (1)。</p>
|
|
<p>包含一个文件时,它将经过<a href="cpp-language-translation_phases.html">翻译阶段</a> 1-4 的处理,这可能递归地包含嵌套 <code>#include</code> 指令的展开,直到一个由实现定义的嵌套限制。为避免(可能传递性地)重复包含相同文件,和由文件包含自身造成的无限递归,通常使用<i>头文件防护</i>:整个头文件被包装在下列结构中</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co2">#ifndef FOO_H_INCLUDED /* 任何唯一地映射到文件的名称 */</span>
|
|
<span class="co2">#define FOO_H_INCLUDED</span>
|
|
<span class="co1">// 文件内容在此</span>
|
|
<span class="co2">#endif</span></pre></div>
|
|
</div>
|
|
<p>许多编译器也会实现有类似效果的非标准 <a href="cpp-preprocessor-impl.html"><tt>pragma</tt></a> <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="co2">#pragma once</span></span></span>:在已经包含相同文件(文件的身份以操作系统指定的方式确定)的时候禁止处理该文件。</p>
|
|
<p>结果是 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="nu0">1</span></span></span> 的 <code>__has_include</code> 只表明存在有指定名称的头或源文件。它并不意味着包含该头或源文件时不会导致错误,或它会包含任何有意义的内容。例如在同时支持 C++14 和 C++17 模式(并在其 C++14 模式作为一项遵从标准的扩展而提供 <span class="t-c"><span class="mw-geshi cpp source-cpp">__has_include</span></span>)的 C++ 实现上,<span class="t-c"><span class="mw-geshi cpp source-cpp">__has_include<span class="br0">(</span><span class="sy1"><</span>optional<span class="sy1">></span><span class="br0">)</span></span></span> 在 C++14 模式中可以是 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="nu0">1</span></span></span>,但实际上 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="co2">#include <optional></span></span></span> 可能导致错误。</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="cpp source-cpp">
|
|
<pre class="de1"><span class="co2">#if __has_include(<optional>)</span>
|
|
<span class="co2"># include <optional></span>
|
|
<span class="co2"># define has_optional 1</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span> <span class="kw1">using</span> optional_t <span class="sy1">=</span> <a href="cpp-utility-optional.html"><span class="kw1075">std::<span class="me2">optional</span></span></a><span class="sy1"><</span>T<span class="sy1">></span><span class="sy4">;</span>
|
|
<span class="co2">#elif __has_include(<experimental/optional>)</span>
|
|
<span class="co2"># include <experimental/optional></span>
|
|
<span class="co2"># define has_optional -1</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span> <span class="kw1">using</span> optional_t <span class="sy1">=</span> <a href="http://zh.cppreference.com/w/cpp/experimental/optional"><span class="kw2299">std::<span class="me2">experimental</span><span class="sy4">::</span><span class="me2">optional</span></span></a><span class="sy1"><</span>T<span class="sy1">></span><span class="sy4">;</span>
|
|
<span class="co2">#else</span>
|
|
<span class="co2"># define has_optional 0</span>
|
|
<span class="co2"># include <utility></span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> V<span class="sy1">></span> <span class="kw1">class</span> optional_t <span class="br0">{</span>
|
|
V v_<span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="kw4">bool</span> has_<span class="br0">{</span><span class="kw2">false</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">public</span><span class="sy4">:</span>
|
|
optional_t<span class="br0">(</span><span class="br0">)</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span>
|
|
optional_t<span class="br0">(</span>V<span class="sy3">&&</span> v<span class="br0">)</span> <span class="sy4">:</span> v_<span class="br0">(</span>v<span class="br0">)</span>, has_<span class="br0">{</span><span class="kw2">true</span><span class="br0">}</span> <span class="br0">{</span><span class="br0">}</span>
|
|
V value_or<span class="br0">(</span>V<span class="sy3">&&</span> alt<span class="br0">)</span> <span class="kw4">const</span><span class="sy3">&</span> <span class="br0">{</span> <span class="kw1">return</span> has_ <span class="sy4">?</span> v_ <span class="sy4">:</span> alt<span class="sy4">;</span> <span class="br0">}</span>
|
|
<span class="coMULTI">/*...*/</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co2">#endif</span>
|
|
|
|
<span class="co2">#include <iostream></span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">if</span> <span class="br0">(</span>has_optional <span class="sy1">></span> <span class="nu0">0</span><span class="br0">)</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"<optional> 存在<span class="es1">\n</span>"</span><span class="sy4">;</span>
|
|
<span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">(</span>has_optional <span class="sy1"><</span> <span class="nu0">0</span><span class="br0">)</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"<experimental/optional> 存在<span class="es1">\n</span>"</span><span class="sy4">;</span>
|
|
<span class="kw1">else</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"<optional> 不存在<span class="es1">\n</span>"</span><span class="sy4">;</span>
|
|
|
|
optional_t<span class="sy1"><</span><span class="kw4">int</span><span class="sy1">></span> op<span class="sy4">;</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"op = "</span> <span class="sy1"><<</span> op.<span class="me1">value_or</span><span class="br0">(</span><span class="sy2">-</span><span class="nu0">1</span><span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
op <span class="sy1">=</span> <span class="nu0">42</span><span class="sy4">;</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"op = "</span> <span class="sy1"><<</span> op.<span class="me1">value_or</span><span class="br0">(</span><span class="sy2">-</span><span class="nu0">1</span><span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</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"><optional> 存在
|
|
op = -1
|
|
op = 42</pre></div>
|
|
</div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<table class="t-dsc-begin">
|
|
<tr class="t-dsc">
|
|
<td colspan="2"><a href="cpp-header.html">C++ 标准库头文件列表</a></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|