1 变参数函数(variadic function)
这种函数需要固定数量的 强制参数(mandatory argument),至少有一个;后面是数量可变的 可选参数(optional argument),可选参数的数量由强制参数的值决定,或由用来定义可选参数列表的特殊值决定。
对于每一个强制参数来说,函数头部都会显示一个适当的参数,像普通函数声明一样。参数列表的格式是强制性参数在前,后面跟着一个逗号和省略号,这个省略号代表可选参数。
可变参数函数要获取可选参数时,必须通过一个 类型为 va_list 的对象,这种类型的对象也称为 参数指针(argument pointer)。它包含了栈中至少一个参数的位置。可以使用这个参数指针从一个可选参数移动到下一个可选参数,由此,函数就可以获取所有的可选参数。va_list 类型被定义在头文件 stdarg.h 中。
2 参数指针及有关的宏
当编写支持参数数量可变的函数时,必须用 va_list 类型定义参数指针,以获取可选参数。在下面的讨论中,va_list 对象被命名为 argptr。可以用 4 个宏来处理该参数指针,这些宏都定义在头文件 stdarg.h 中:
va_start
void va_start(va_list argptr, lastparam);
使用第一个可选参数的位置来初始化 argptr 参数指针。该宏的第二个参数必须是该函数最后一个有名称参数的名称。必须先调用该宏,才可以开始使用可选参数。
va_arg
type va_arg(va_list argptr, type);
展开宏 va_arg 会得到当前 argptr 所引用的可选参数,也会将 argptr 移动到列表中的下一个参数。宏 va_arg 的第二个参数是刚刚被读入的参数的类型。
va_end
void va_end(va_list argptr);
当不再需要使用参数指针时,必须调用宏 va_end。如果想使用宏 va_start 或者宏 va_copy 来重新初始化一个之前用过的参数指针,也必须先调用宏 va_end。
va_copy
void va_copy(va_list dest, va_list src);
宏 va_copy 使用当前的 src 值来初始化参数指针 dest。然后就可以使用 dest 中的备份获取可选参数列表,从 src 所引用的位置开始。
例1:
// 函数add() 计算可选参数之和
// 参数:第一个强制参数指定了可选参数的数量,可选参数为double类型
// 返回值:和值,double类型
double add( int n, ... )
{
int i = 0;
double sum = 0.0;
va_list argptr;
va_start( argptr, n ); // 初始化argptr
for ( i = 0; i < n; ++i ) // 对每个可选参数,读取类型为double的参数,
sum += va_arg( argptr, double ); // 然后累加到sum中
va_end( argptr );
return sum;
}
例2:
#include <stdarg.h>
#include <stdio.h>
void std_vararg_func(const char *format, ...)
{
va_list ap;
va_start(ap, format);
printf("%d\n", va_arg(ap, int));
printf("%f\n", va_arg(ap, double));
printf("%s\n", va_arg(ap, char*));
va_end(ap);
}
int main()
{
std_vararg_func("%d %f %s\n", 4, 5.4, "hello world");
return 0;
}
参考博客:
https://www.cnblogs.com/cpoint/p/3368993.html
3 变参函数printf
原型:
int printf(const char *format, ...);
成功调用printf函数后,系统会分配一段栈帧存放所有的局部变量(含形参),待打印时按照格式控制符输出。
函数形参在栈中分配内存的顺序:从右到左,运算存储的值也是从右到左。
如:
printf("%d%c%lf\n", 100, 'x', 3.14);
实例:
#include<stdio.h>
int main(void)
{
char a='A';
int b=20;
printf("%d,%o\n",(a=a+a, (void)(a+b), b), a+'a'-'A',b);
printf("%d %d\n", a, b);
printf("%d,%o\n", a+'a'-'A',(a=a+a, (void)(a+b), b),b++);
printf("%d %d\n", a, b)
}
//输出
20,141
-126 20
36,25
4 21
- 第一次打印:
a+'a'-'A'='a'=97=0141;
(a=a+a, a+b, b):a=65+65=130(int)=-126(char),逗号表达式的值为:b=20。 - 第二次打印:
a=-126(char);b=20; - 第三次打印:
b++: b=21;
(a=a+a, a+b, b):a=260(int)=4(char),b=21=025
a+'a'-'A'=4+97-65=36 - 第四次打印:
a=4;b=21;
3.1 强制参数的多种形式:
一般都是类似:"%d",还可以是下面这种:
#include<stdio.h>
int main(int argc, char *argv[])
{
char p1[] = "abcd\n";
char p2[] = "ab%d\n"; //后面打印的数值是个随机值
printf(p1);
printf(p2);
return 0;
}
//输出
abcd
ab6299664