167 lines
17 KiB
HTML
167 lines
17 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_name_space 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>在 C 程序中遇到<a href="c-language-identifier.html">标识符</a>时,会查找定位引入该标识符,并且当前<a href="c-language-scope.html">在作用域内</a>的<a href="c-language-declarations.html">声明</a>。若同一标识符的多个声明属于称作“命名空间”的相异类别,则 C 允许它们同时存在于作用域内:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 标号命名空间:所有声明为<a href="c-language-statements.html#.E6.A0.87.E5.8F.B7">标号</a>的标识符。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 标签名:所有声明为 <a href="c-language-struct.html">struct</a> 、 <a href="c-language-union.html">union</a> 及<a href="c-language-enum.html">枚举类型</a>名称的标识符。注意所有这三种标签共享同一命名空间。</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 成员名:所有声明为至少为一个 <a href="c-language-struct.html">struct</a> 或 <a href="c-language-union.html">union</a> 成员的标识符。每个结构体和联合体引入它自己的这种命名空间。</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c23">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">4)</span> 全局属性命名空间:标准定义的<a href="c-language-attributes.html">属性记号</a>或实现定义的属性前缀。</div>
|
|
<div class="t-li1"><span class="t-li">5)</span> 非标准属性名:后随属性前缀的属性名。每个属性前缀拥有分离的、它所引入的实现定义属性所在的命名空间。</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c23">(C23 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">6)</span> 所有其他标识符,称之为“通常标识符”以别于 <span class="t-v">(1-5)</span> (函数名、对象名、 typedef 名、枚举常量)。</div>
|
|
<p>在查找点,根据使用方式确定标识符所属的命名空间:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 作为 <a href="c-language-goto.html">goto 语句</a>运算数出现的标识符,会在标号命名空间中查找。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 后随关键词 <span class="t-c"><span class="mw-geshi c source-c"><span class="kw1">struct</span></span></span> 、 <span class="t-c"><span class="mw-geshi c source-c"><span class="kw1">union</span></span></span> 或 <span class="t-c"><span class="mw-geshi c source-c"><span class="kw2">enum</span></span></span> 的标识符,会在标签命名空间中查找。</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 后随<a href="c-language-operator_member_access.html">成员访问</a>或通过指针的成员访问运算符的标识符,会在类型成员命名空间中查找,该类型由成员访问运算符左运算数确定。</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c23">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">4)</span> 直接出现于属性说明符( <span class="t-c"><span class="mw-geshi c source-c"><span class="br0">[</span><span class="br0">[</span>...<span class="br0">]</span><span class="br0">]</span></span></span> )中的标识符,会在全局属性命名空间中查找。</div>
|
|
<div class="t-li1"><span class="t-li">5)</span> 后随属性前缀之后的 <span class="t-c"><span class="mw-geshi c source-c"><span class="sy4">::</span></span></span> 记号的标识符,会在属性前缀所引入命名空间中查找。</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c23">(C23 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">6)</span> 所有其他标识符,会在通常命名空间中查找。</div>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<p><a href="c-preprocessor-replace.html">宏</a>名不是任何命名空间的一部分,因为语义分析前,预处理器会替换它们。</p>
|
|
<p>一个常见举措是将 struct/union/enum 名称注入通常命名空间,以 <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">struct</span> A <span class="br0">{</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 于标签命名空间中引入名称A</span>
|
|
<span class="kw1">typedef</span> <span class="kw1">struct</span> A A<span class="sy4">;</span> <span class="co1">// 首先,对"struct"后A的查找找到标签命名空间的一个</span>
|
|
<span class="co1">// 然后将名称A引入通常命名空间</span>
|
|
<span class="kw1">struct</span> A<span class="sy2">*</span> p<span class="sy4">;</span> <span class="co1">// OK,此A于标签命名空间中查找</span>
|
|
A<span class="sy2">*</span> q<span class="sy4">;</span> <span class="co1">// OK,此A于通常命名空间中查找</span></pre></div>
|
|
</div>
|
|
<p>众所周知的一个同一标识符横跨两个命名空间使用的示例,是 POSIX 头文件 <code>sys/stat.h</code> 中的标识符 <span class="t-c"><span class="mw-geshi c source-c">stat</span></span> 。它用作通常标识符时<a rel="nofollow" class="external text" href="http://pubs.opengroup.org/onlinepubs/9699919799/">指名一个函数</a>,而在用作标签时<a rel="nofollow" class="external text" href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html">指代一个结构体</a>。</p>
|
|
<p>不同于 C++ 中,枚举常量不是结构体成员,而且其命名空间是通常标识符的命名空间,故而 C 中无结构体作用域,其作用域是出现结构体声明的作用域:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw1">struct</span> tagged_union
|
|
<span class="br0">{</span>
|
|
<span class="kw2">enum</span> <span class="br0">{</span>INT, FLOAT, STRING<span class="br0">}</span> type<span class="sy4">;</span>
|
|
<span class="kw4">int</span> integer<span class="sy4">;</span>
|
|
<span class="kw4">float</span> floating_point<span class="sy4">;</span>
|
|
<span class="kw4">char</span> <span class="sy2">*</span>string<span class="sy4">;</span>
|
|
<span class="br0">}</span> tu<span class="sy4">;</span>
|
|
|
|
tu.<span class="me1">type</span> <span class="sy1">=</span> INT<span class="sy4">;</span> <span class="co1">// C 中 OK , C++ 中错误</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c23">
|
|
<td>
|
|
<p>若不支持标准属性、属性前缀或非标准属性名,则忽略非法的属性自身而不导致错误。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c23">(C23 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<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="kw4">void</span> foo <span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// 通常命名空间,文件作用域</span>
|
|
<span class="kw1">struct</span> foo <span class="br0">{</span> <span class="co1">// 标签命名空间,文件作用域</span>
|
|
<span class="kw4">int</span> foo<span class="sy4">;</span> <span class="co1">// 此 struct foo 的成员命名空间,文件作用域</span>
|
|
<span class="kw2">enum</span> bar <span class="br0">{</span> <span class="co1">// 标签命名空间,文件作用域</span>
|
|
RED <span class="co1">// 通常命名空间,文件作用域</span>
|
|
<span class="br0">}</span> bar<span class="sy4">;</span> <span class="co1">// 此 struct foo 的成员命名空间,文件作用域</span>
|
|
<span class="kw1">struct</span> foo<span class="sy2">*</span> p<span class="sy4">;</span> <span class="co1">// OK :使用标签/文件作用域名称 "foo"</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw2">enum</span> bar x<span class="sy4">;</span> <span class="co1">// OK :使用标签/文件作用域 "bar"</span>
|
|
<span class="co1">// int foo; // 错误:通常命名空间已有 foo</span>
|
|
<span class="co1">//union foo { int a, b; }; // 错误:标签命名空间已有 foo 在作用域中</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="kw1">goto</span> foo<span class="sy4">;</span> <span class="co1">// OK 从标号命名空间/函数作用域使用 "foo"</span>
|
|
|
|
<span class="kw1">struct</span> foo <span class="br0">{</span> <span class="co1">// 标签命名空间,块作用域(于文件作用域中隐藏)</span>
|
|
<span class="kw2">enum</span> bar x<span class="sy4">;</span> <span class="co1">// OK ,从标签命名空间/文件作用域使用 "bar"</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">typedef</span> <span class="kw1">struct</span> foo foo<span class="sy4">;</span> <span class="co1">// OK :从标签命名空间/块作用域使用 foo</span>
|
|
<span class="co1">// 定义块作用域通常命名空间的 foo (隐藏于文件作用域)</span>
|
|
<span class="br0">(</span>foo<span class="br0">)</span><span class="br0">{</span>.<span class="me1">x</span><span class="sy1">=</span>RED<span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 使用通常命名空间/块作用域 foo 和通常命名空间/文件作用域 RED</span>
|
|
|
|
foo<span class="sy4">:;</span> <span class="co1">// 标号命名空间,函数作用域</span>
|
|
<span class="br0">}</span></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.2.3 Name spaces of identifiers (p: 29-30)</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.2.3 Name spaces of identifiers (p: 37)</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.2.3 Name spaces of identifiers (p: 31)</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.1.2.3 Name spaces of identifiers</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>
|