IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C/C++可变参数列表参数处理方法 -> 正文阅读

[C++知识库]C/C++可变参数列表参数处理方法

C/C++可变参数列表参数处理(va_list、va_start()、va_copy()、va_arg()、va_end())

1 引言

??在学习 C/C++ 的过程中经常会看到一些函数,使用的是可变参数列表,函数在定义是,没有规定参数个数与参数类型,而是使用 ... 代替。如果是第一次见到这种表达方式吗,可能会感到很神奇。这里的 ... 就代表了可变参数列表部分。
??这种方式允许函数接受类型和数目不确定的一些列参数,那么函数内部是如何对可变的参数列表进行处理的呢?这里对可变参数列表的处理,就需要用到 va_listva_startva_copyva_argva_end 。接下来分别对它们进行介绍。

2 类型、函数介绍

2.1 va_list

??对应的定义如下:

	typedef /* unspecified */ va_list;  /* 未指定具体类型 */

??这里的 va_list 是一个完整对象类型(complete object type),用来保存 va_start, va_copy, va_arg, va_end 这些函数需要的数据。
??如果创建了一个 va_list 实例,它被传递给另一个函数,并且在该函数中通过 va_arg() 使用,那么用在调用函数中的任意后续参数都应该在调用 va_end() 之前被处理。
??可以把指向 va_list 类型的指针传递给另一个函数,然后在函数返回后使用该对象,也就是说,可以使用指针访问该类型对象。

2.2 va_start()

??函数对应的定义如下:

	void va_start( std::va_list ap, parm_n );

??这个宏定义能够使 va_list 类型的对象能够访问可变参数列表,使 va_list 对象指向可变参数列表可变部分的前一个参数(也就是最后一个固定的参数,说可变部分,是因为整个括号内的函数的参数一起才称之为可变参数列表,而前边的参数往往是固定的,可变部分在整个参数列表的后边)。这实际上是一个初始化的过程,我们可以理解为,这个函数告知 va_list 类型的对象从哪个参数开始是参数列表中可变的部分,让它知道从哪里开始工作,便于后续进行逐个访问使用。
??这里的 parm_n 通常是可变参数 ... 前边的一个参数,这里的 ap 经过 va_start() 函数初始化之后,指向 ... 部分对应的第一个参数。
??va_start() 应该在任意的 va_arg() 调用前被 va_list 类型的对象调用,注意这里不是必须要调用 va_start() 函数,还可以使用 va_copy() ,后续会进行介绍,两个宏函数根据需要在调用 va_arg() 函数前有调用即可。

2.3 va_copy()

??函数对应的定义如下:

	void va_copy( std::va_list dest, std::va_list src ); // C++11、C99引入

??结合函数定义,很容易可以理解,这是一个将已有的 va_list 类型对象内容拷贝到另一个 va_list 类型对象的过程,这个过程与调用 va_start() 函数进行初始化由相同的作用。
??va_end() 应该在函数返回之前或者任意子序列重新被初始化之前被 dest 调用。这里也不难理解,函数返回之前,即 va_list 对象已经完成了本次的“任务”,需要清理一下;dest 中的部分参数重新初始化之前也是如此,也需要调用 va_end() 函数进行清理工作。

2.4 va_arg()

??函数对应的定义如下:

	T va_arg( std::va_list ap, T );

??va_arg() 宏函数根据 va_list 类型对象的下一个参数展开为类型 T 的表达式,移动指针,将 va_list 对象的指针指向可变参数列表中的下一个参数。
??在调用 va_arg 之前,va_list 类型的对象必须经过 va_startva_copy() 的初始化,且不能有调用 va_end(),每次调用 va_arg() 会将 va_list 对象的指针指向可变参数列表中的下一个参数。
??如果可变参数列表中的下一个参数与类型 T 不兼容,行为未定义,除非:

  • 一种类型是有符号整型,另一种类型是相应的无符号整型,值在两种类型中都可以表示;
  • 一种类型是指向void的指针,另一种类型是指向字符类型(char、signed char或unsigned char)的指针。
    ??如果va_arg() 调用的时候 va_list 类型对象(也称为实例)中已经没有参数了,对应的行为也没有定义。
2.5 va_end()

??函数对应的定义如下:

	void va_end( std::va_list ap );

??va_end() 对由 va_start() 或者 va_copy() 初始化的 va_list 类型对象的执行清理过程。va_end() 会修改 va_list 对象实例,使其不再可用。
??如果没有相对应的对 va_start() 或者 va_copy() 函数的调用,或者如果在一个函数调用 va_start() 或者 va_copy() 函数之前没有调用 va_end() ,行为没有定义,即在这些情况下,没有定义如何去处理。

3 示例

#include <iostream>
#include <cstdarg>
 
int add_nums(int count, ...) 
{
    int result = 0;
    std::va_list args;						/* 创建一个 va_list 实例 */
    va_start(args, count);					/* 对实例进行初始化,这里的count是可变参数列表的第一个参数,而调用va_start()函数之后,args实际指向count */
    for (int i = 0; i < count; ++i) {
        result += va_arg(args, int);		/* 读取args指向位置的下一个参数,扩展为int类型,并移动指针到下一个位置 */
    }
    va_end(args);							/* 清理va_list实例 */
    return result;
}
 
int main() 
{
    std::cout << add_nums(4, 25, 25, 50, 50) << '\n';
}

4 总结

??va_listva_start()va_copy()va_arg()va_end() 是可变参数列表处理过程中使用到的数据类型和处理方法, va_list 是用于处理可变参数的数据,va_start()、**va_copy()**则负责对该数据对象进行初始化,va_arg() 则负责对可变参数按照指定类型进行扩展,并移动指针,va_end() 负责对该数据进行清理工作。把这些放在一个流程中进行理解,应该回容易一些。

参考文章:

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-07-17 16:02:42  更:2022-07-17 16:03:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/12 3:06:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码