雪山飞鹰 發表於 2025-8-31 14:12:00

C语言之可变参数列表

<p>在 C 语言中,可变参数列表(Variable Argument List)通过 <code>stdarg.h</code> 头文件提供的宏和函数来实现。它允许函数接受可变数量的参数,类似于 <code>printf</code> 和 <code>scanf</code> 这样的函数。本文介绍与可变参数列表相关的函数和用法。</p>

<hr>
<h2 id="核心宏和函数">核心宏和函数</h2>
<p><code>stdarg.h</code> 提供了以下宏和函数来处理可变参数列表:</p>
<table>
<thead>
<tr>
<th>宏/函数</th>
<th>作用</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>va_list</code></td>
<td>定义一个变量,用于存储可变参数列表。</td>
</tr>
<tr>
<td><code>va_start()</code></td>
<td>初始化 <code>va_list</code>,使其指向可变参数列表的第一个参数。</td>
</tr>
<tr>
<td><code>va_arg()</code></td>
<td>从 <code>va_list</code> 中获取下一个参数,并指定其类型。</td>
</tr>
<tr>
<td><code>va_end()</code></td>
<td>清理 <code>va_list</code>,结束可变参数列表的访问。</td>
</tr>
<tr>
<td><code>va_copy()</code></td>
<td>复制一个 <code>va_list</code>(C99 标准引入)。</td>
</tr>
</tbody>
</table>
<hr>
<h2 id="使用步骤">使用步骤</h2>
<p>使用可变参数列表的典型步骤如下:</p>
<ol>
<li>定义一个 <code>va_list</code> 类型的变量。</li>
<li>使用 <code>va_start()</code> 初始化 <code>va_list</code>。</li>
<li>使用 <code>va_arg()</code> 逐个获取参数。</li>
<li>使用 <code>va_end()</code> 清理 <code>va_list</code>。</li>
</ol>
<hr>
<h2 id="示例代码">示例代码</h2>
<p>以下是一个简单的示例,演示如何使用可变参数列表实现一个求和函数:</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;stdarg.h&gt;

// 定义一个可变参数函数,计算任意数量整数的和
int sum(int count, ...) {
    int total = 0;
    va_list args;// 定义 va_list 变量

    va_start(args, count);// 初始化 args,使其指向第一个可变参数

    for (int i = 0; i &lt; count; i++) {
      int num = va_arg(args, int);// 获取下一个 int 类型的参数
      total += num;
    }

    va_end(args);// 清理 args

    return total;
}

int main() {
    printf("Sum: %d\n", sum(3, 10, 20, 30));// 输出 60
    printf("Sum: %d\n", sum(5, 1, 2, 3, 4, 5));// 输出 15
    return 0;
}
</code></pre>
<hr>
<h2 id="详细说明">详细说明</h2>
<h3 id="1-va_list">(1) <code>va_list</code></h3>
<ul>
<li>
<p>类型:<code>va_list</code> 是一个类型,用于存储可变参数列表。</p>
</li>
<li>
<p>示例:</p>
<pre><code class="language-c">va_list args;
</code></pre>
</li>
</ul>
<h3 id="2-va_start">(2) <code>va_start()</code></h3>
<ul>
<li>
<p>函数原型:</p>
<pre><code class="language-c">void va_start(va_list ap, last_arg);
</code></pre>
</li>
<li>
<p>概念实现:</p>
<pre><code class="language-C">// 概念性实现(实际由编译器提供)
#define va_start(ap, last_arg) \
(ap = (va_list)((char*)&amp;last_arg + sizeof(last_arg)))
</code></pre>
</li>
<li>
<p>作用:</p>
<ul>
<li>初始化 <code>va_list</code>,使其指向可变参数列表的第一个参数。</li>
<li><code>last_arg</code> 是可变参数列表前的最后一个固定参数。</li>
</ul>
</li>
<li>
<p>示例:</p>
<pre><code class="language-c">va_start(args, count);
</code></pre>
</li>
</ul>
<h3 id="3-va_arg">(3) <code>va_arg()</code></h3>
<ul>
<li>
<p>函数原型:</p>
<pre><code class="language-c">type va_arg(va_list ap, type);
</code></pre>
</li>
<li>
<p>作用:</p>
<ul>
<li>从 <code>va_list</code> 中获取下一个参数,并指定其类型。</li>
<li><code>type</code> 是参数的类型(如 <code>int</code>、<code>double</code> 等)。</li>
</ul>
</li>
<li>
<p>示例:</p>
<pre><code class="language-c">int num = va_arg(args, int);
</code></pre>
</li>
</ul>
<h3 id="4-va_end">(4) <code>va_end()</code></h3>
<ul>
<li>
<p>函数原型:</p>
<pre><code class="language-c">void va_end(va_list ap);
</code></pre>
</li>
<li>
<p>作用:清理 <code>va_list</code>,结束可变参数列表的访问。</p>
</li>
<li>
<p>示例:</p>
<pre><code class="language-c">va_end(args);
</code></pre>
</li>
</ul>
<h3 id="5-va_copyc99-引入">(5) <code>va_copy()</code>(C99 引入)</h3>
<ul>
<li>
<p>函数原型:</p>
<pre><code class="language-c">void va_copy(va_list dest, va_list src);
</code></pre>
</li>
<li>
<p>作用:</p>
<ul>
<li>复制一个 <code>va_list</code> 变量。</li>
<li><code>dest</code> 是目标变量,<code>src</code> 是源变量。</li>
</ul>
</li>
<li>
<p>示例:</p>
<pre><code class="language-c">va_list args_copy;
va_copy(args_copy, args);
</code></pre>
</li>
</ul>
<hr>
<h2 id="注意事项">注意事项</h2>
<ol>
<li><strong>固定参数</strong>:可变参数函数必须至少有一个固定参数(如 <code>count</code>),用于确定可变参数的数量或类型。</li>
<li><strong>参数类型</strong>:使用 <code>va_arg()</code> 时,必须明确指定参数的类型。如果类型不匹配,会导致未定义行为。</li>
<li><strong>参数数量</strong>:需要确保访问的参数数量不超过实际传递的参数数量,否则会导致未定义行为。</li>
<li><strong>平台依赖性</strong>:可变参数列表的实现依赖于底层平台,不同平台可能有不同的行为。</li>
</ol>
<hr>
<h2 id="更复杂的示例">更复杂的示例</h2>
<p>以下是一个更复杂的示例,实现一个类似 <code>printf</code> 的函数,支持格式化输出:</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;stdarg.h&gt;

void my_printf(const char *format, ...) {
    va_list args;
    va_start(args, format);

    while (*format) {
      if (*format == '%') {
            format++;// 跳过 '%'
            switch (*format) {
                case 'd': {
                  int num = va_arg(args, int);
                  printf("%d", num);
                  break;
                }
                case 'f': {
                  double num = va_arg(args, double);
                  printf("%f", num);
                  break;
                }
                case 's': {
                  char *str = va_arg(args, char *);
                  printf("%s", str);
                  break;
                }
                default:
                  putchar(*format);
                  break;
            }
      } else {
            putchar(*format);
      }
      format++;
    }

    va_end(args);
}

int main() {
    my_printf("Integer: %d, Float: %f, String: %s\n", 42, 3.14, "Hello");
    return 0;
}
</code></pre>
<hr>
<h2 id="总结">总结</h2>
<ul>
<li><code>va_list</code> 是处理可变参数列表的核心类型。</li>
<li><code>va_start()</code>、<code>va_arg()</code> 和 <code>va_end()</code> 是处理可变参数的基本宏。</li>
<li>可变参数函数需要至少一个固定参数,用于确定可变参数的数量或类型。</li>
<li>使用可变参数时需要注意参数类型和数量的匹配,避免未定义行为。</li>
</ul><br><br>
来源:https://www.cnblogs.com/neozhuang/p/19066856/c-variable-argument-lists
頁: [1]
查看完整版本: C语言之可变参数列表