260 lines
22 KiB
HTML
260 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>函数定义</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_function_definition 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>函数定义将函数体(声明与语句的序列)与函数名及参数列表关联。不同于<a href="c-language-function_declaration.html">函数声明</a>,函数定义只允许在文件作用域(不存在嵌套函数)。</p>
|
|
<p>C 支持二种函数定义的形式:</p>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><span class="t-spar">属性说明符序列</span><span class="t-mark">(可选)</span> <span class="t-spar">说明符与限定符</span> <span class="t-spar">形参列表声明符</span> <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><span class="t-spar">说明符与限定符</span> <span class="t-spar">标识符列表声明符</span> <span class="t-spar">声明列表</span> <span class="t-spar">函数体</span></td>
|
|
<td>(2)</td>
|
|
<td><span class="t-mark-rev t-until-c23">(C23 前)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<p>其中</p>
|
|
<table class="t-par-begin">
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">属性说明符序列</span></td>
|
|
<td>-</td>
|
|
<td><span class="t-mark-rev t-since-c23">(C23)</span>可选的<a href="c-language-attributes.html">属性</a>列表,应用到函数</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">说明符与限定符</span></td>
|
|
<td>-</td>
|
|
<td>下列的组合
|
|
<ul>
|
|
<li><a href="c-language-declarations.html">类型说明符</a>,可由声明器修改,组成<i>返回类型</i></li>
|
|
<li><a href="c-language-storage_duration.html">存储类说明符</a>,确定标识符的链接( <code>static</code> 、 <code>extern</code> 或无)</li>
|
|
<li>函数说明符( <a href="c-language-inline.html"><code>inline</code></a> 、 <a href="c-language-_Noreturn.html"><code>_Noreturn</code></a> 或无)</li>
|
|
</ul>
|
|
</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">形参列表声明符</span></td>
|
|
<td>-</td>
|
|
<td>用<a href="c-language-function_declaration.html">参数列表</a>指代函数参数的函数类型的声明器</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">标识符列表声明符</span></td>
|
|
<td>-</td>
|
|
<td>用<a href="c-language-function_declaration.html">标识符列表</a>指代函数参数的函数类型的声明器</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">声明列表</span></td>
|
|
<td>-</td>
|
|
<td>在 <span class="t-spar">标识符列表声明符</span> 中声明每个参数的声明序列。这些声明不能使用初始化器,而且仅允许 <span class="t-c"><span class="mw-geshi c source-c"><span class="kw4">register</span></span></span> 作为<a href="c-language-storage_duration.html">存储类说明符</a>。</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">函数体</span></td>
|
|
<td>-</td>
|
|
<td><a href="c-language-statements.html#.E5.A4.8D.E5.90.88.E8.AF.AD.E5.8F.A5">复合语句</a>,是花括号所包括的声明及语句序列,只要调用此函数就会被执行</td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">1)</span> 新式 (C89) 函数定义。此定义引入函数自身,并为任何将来的<a href="c-language-operator_other.html#.E5.87.BD.E6.95.B0.E8.B0.83.E7.94.A8">函数调用表达式</a>提供函数原型,强迫从实参表达式转换到声明形参类型。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">int</span> max<span class="br0">(</span><span class="kw4">int</span> a, <span class="kw4">int</span> b<span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">return</span> a<span class="sy1">></span>b<span class="sy4">?</span>a<span class="sy4">:</span>b<span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw4">double</span> g<span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">return</span> <span class="nu16">0.1</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> <span class="t-mark-rev t-until-c23">(C23 前)</span> 旧式 (K&R) 函数定义。此定义不表现为原型,而任何将来的<a href="c-language-operator_other.html#.E5.87.BD.E6.95.B0.E8.B0.83.E7.94.A8">函数调用表达式</a>将进行默认参数提升。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">int</span> max<span class="br0">(</span>a, b<span class="br0">)</span>
|
|
<span class="kw4">int</span> a, b<span class="sy4">;</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">return</span> a<span class="sy1">></span>b<span class="sy4">?</span>a<span class="sy4">:</span>b<span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="kw4">double</span> g<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">return</span> <span class="nu16">0.1</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<p>同<a href="c-language-function_declaration.html">函数声明</a>,函数的返回类型由 <span class="t-spar">说明符与限定符</span> 中的类型说明符确定,并像在<a href="c-language-declarations.html">声明</a>中一样可以由 <span class="t-spar">声明符</span> 修改。返回类型必须是完整的非数组对象类型或 <span class="t-c"><span class="mw-geshi c source-c"><span class="kw4">void</span></span></span> 类型。若返回类型会有 cvr 限定,则为构造函数类型的目的,将它调整为其无限定版本。</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">char</span> <span class="sy2">*</span>s<span class="br0">)</span> <span class="br0">{</span> <a href="c-io-puts.html"><span class="kw836">puts</span></a><span class="br0">(</span>s<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// 返回类型为 void</span>
|
|
<span class="kw4">int</span> sum<span class="br0">(</span><span class="kw4">int</span> a, <span class="kw4">int</span> b<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> a<span class="sy2">+</span>b<span class="sy4">:</span> <span class="br0">}</span> <span class="co1">// 返回类型为int</span>
|
|
<span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span>foo<span class="br0">(</span><span class="kw4">const</span> <span class="kw4">void</span> <span class="sy2">*</span>p<span class="br0">)</span><span class="br0">)</span><span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span> <span class="br0">{</span> <span class="co1">// 返回类型是指向 3 个 int 的数组的指针</span>
|
|
<span class="kw1">return</span> <a href="c-memory-malloc.html"><span class="kw403">malloc</span></a><span class="br0">(</span><span class="kw4">sizeof</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>同<a href="c-language-function_declaration.html">函数声明</a>,为构造函数类型的目的,将参数类型从函数调整到指针,从数组调整到指针,并且为确定<a href="c-language-type.html#.E5.85.BC.E5.AE.B9.E7.B1.BB.E5.9E.8B" class="mw-redirect">兼容函数类型</a>的目的,忽略所有参数类型的顶层 cvr 限定符。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-c23">
|
|
<td>
|
|
<p>不同于<a href="c-language-function_declaration.html">函数声明</a>,不允许无名形参(否则旧式 (K&R) 函数定义中会有冲突),即使不在函数中使用也必须命名它们。仅有的例外是参数列表 <span class="t-c"><span class="mw-geshi c source-c"><span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span></span></span> 。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-c23">(C23 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-c23">
|
|
<td>
|
|
<p>函数定义中形参可以为无名,因为旧式 (K&R) 函数定义已被移除。函数体内不能以名称访问无名形参。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c23">(C23 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">int</span>, <span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 声明</span>
|
|
<span class="co1">// int f(int, int) { return 7; } // C23 前错误, C23 起 OK</span>
|
|
<span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">int</span> a, <span class="kw4">int</span> b<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="nu0">7</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// 定义</span>
|
|
<span class="kw4">int</span> g<span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="nu0">8</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// OK : void 不声明参数</span></pre></div>
|
|
</div>
|
|
<p>在函数体内,每个具名参数都是<a href="c-language-value_category.html">左值</a>表达式,它们拥有自动<a href="c-language-storage_duration.html">存储期</a>和<a href="c-language-scope.html">块作用域</a>。参数在内存中的布局(或者它们究竟是否存储于内存中)是未指定的:这是<a href="https://en.wikipedia.org/wiki/Calling_convention" class="extiw" title="enwiki:Calling convention">调用约定</a>的一部分。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">int</span> main<span class="br0">(</span><span class="kw4">int</span> ac, <span class="kw4">char</span> <span class="sy2">**</span>av<span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
ac <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> <span class="co1">// 参数是左值</span>
|
|
av <span class="sy1">=</span> <span class="br0">(</span><span class="kw4">char</span> <span class="sy2">*</span><span class="br0">[</span><span class="br0">]</span><span class="br0">)</span><span class="br0">{</span><span class="st0">"abc"</span>, <span class="st0">"def"</span>, <a href="c-types-NULL.html"><span class="kw103">NULL</span></a><span class="br0">}</span><span class="sy4">;</span>
|
|
f<span class="br0">(</span>ac, av<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>函数调用机制上的其他细节见<a href="c-language-operator_other.html#.E5.87.BD.E6.95.B0.E8.B0.83.E7.94.A8">函数调用运算符</a>,关于从函数返回,见 <a href="c-language-return.html">return</a> 。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c99">
|
|
<td>
|
|
<h3><span class="mw-headline" id="func">__func__</span></h3>
|
|
<p>在每个 <span class="t-spar">函数体</span> 内,拥有块作用域和静态存储期的预定义变量 <span class="t-c"><span class="mw-geshi c source-c">__func__</span></span> 可用,它如同立即通过以下方式在开花括号后定义:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">static</span> <span class="kw4">const</span> <span class="kw4">char</span> __func__<span class="br0">[</span><span class="br0">]</span> <span class="sy1">=</span> <span class="st0">"function name"</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>此特殊标识符有时与<a href="c-preprocessor-replace.html">预定义宏常量</a> <span class="t-c"><span class="mw-geshi c source-c">__FILE__</span></span> 及 <span class="t-c"><span class="mw-geshi c source-c">__LINE__</span></span> 结合使用,例如为 <span class="t-lc"><a href="c-error-assert.html">assert</a></span> 所用。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c99">(C99 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<p>参数列表必须显式存在于声明器中,不能从 typedef 继承它</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> p<span class="br0">(</span><span class="kw4">int</span> q, <span class="kw4">int</span> r<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// p 是类型为 int(int, int) 的函数</span>
|
|
p f <span class="br0">{</span> <span class="kw1">return</span> q <span class="sy2">+</span> r<span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// 错误</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-c99">
|
|
<td>
|
|
<p>C89 中, <span class="t-spar">说明符与限定符</span> 是可选的,若省略它,则函数返回类型默认为 <span class="t-c"><span class="mw-geshi c source-c"><span class="kw4">int</span></span></span> (可由 <span class="t-spar">声明符</span> 修改)。</p>
|
|
<p>另外,旧式定义不要求在 <span class="t-spar">声明列表</span> 中声明每个参数。任何缺少声明的参数拥有 <span class="t-c"><span class="mw-geshi c source-c"><span class="kw4">int</span></span></span> 类型</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1">max<span class="br0">(</span>a, b<span class="br0">)</span> <span class="co1">// a 和 b 拥有 int 类型,返回类型为 int</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">return</span> a<span class="sy1">></span>b<span class="sy4">?</span>a<span class="sy4">:</span>b<span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-c99">(C99 前)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E7.BC.BA.E9.99.B7.E6.8A.A5.E5.91.8A">缺陷报告</span></h3>
|
|
<p>下列更改行为的缺陷报告追溯地应用于以前出版的 C 标准。</p>
|
|
<table class="dsctable" style="font-size:0.8em">
|
|
<tr>
|
|
<th>DR</th>
|
|
<th>应用于</th>
|
|
<th>出版时的行为</th>
|
|
<th>正确行为</th>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2396.htm#dr_423">DR 423</a></td>
|
|
<td>C89</td>
|
|
<td>返回类型可以有限定</td>
|
|
<td>返回类型被隐式除去限定</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.9.1 Function definitions (p: 113-115)</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.9.1 Function definitions (p: 156-158)</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.9.1 Function definitions (p: 141-143)</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.7.1 Function definitions</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>
|