学习笔记分享

分享与展示个人专业知识学习笔记

0%

C语言可变参数

在C语言中想在函数参数列表中传入不固定数量和类型的参数,可以使用stdarg.h头文件,该头文件定义了一系列宏用以实现可变参数列表。

实际上,最熟悉的printfscanf函数就是这么实现的。

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdarg.h>					// 包含该头文件

int sum(int n_elements, ...) // 给出一个命名(有名称的)参数,一串省略号
{
int sum = 0;

va_list var_arg; // 声明一个va_list类型变量

va_start(var_arg, n_elements); // 初始化该变量

for (int i=0;i<n_elements;i++)
{
sum += va_arg(var_arg, int);// 访问参数
}

va_end(var_arg); // 结束访问

return sum;
}
  1. 在函数参数列表中,提供一或多个有名称的参数,最后跟上...提示此处传递数量和类型未知的参数。
  2. va_list类型声明一个变量用于访问可变参数列表。
  3. va_start()接受一个va_list变量和最后一个有名称参数用于初始化,将该va_list变量设置为指向第一个可变参数列表的参数(由给定的最后一个有名称的参数通过相对偏移来确定位置)。
  4. va_arg()接受一个va_list变量和类型名称,按类型返回当前位置参数的值,并将va_list变量向后移动。
  5. va_end()用于将va_list置空,并完成一些清理工作。

注意

  1. 可变参数传递过程中会发生默认参数提升,也就是说没有char/short/float型,因为它们已经被提升了。(详见默认参数提升或见**参考**部分相关文章)现在编译器很智能,当你试图使用这些类型访问时会给出警告:使用char/short/float访问va_arg
  2. va_end()是必须的。有人认为va_end()是不必要的,因为其编译环境下该函数只作了对va_list置空操作。但不同编译环境下,有可能va_start()可能以某种方式修改了堆栈,这种修改可能导致返回无法完成va_end()会将其复原;当然也可能有其他实现。因此,基于可移植性的考虑,va_end当然是必须的。

参考

  1. 《Pointers On C》
  2. 可变长参数列表误区与陷阱——va_arg不可接受的类型
  3. 可变长参数列表误区与陷阱——va_end是必须的吗?
创作不易,支持一下吧!