vsprintf 函数研究--可变参数列表
函数原型:
int vsprintf(char *string, char *format, va_list param);
看不懂的就是va_list
找一个实例代码做测试, 如下例.
$ cat main.cpp
#include <stdio.h>
#include <stdarg.h>
char str[50];
/* 这个函数是可变参数的, 其堆栈可以传递很多参数 */
int vspf(const char*fmt,...)
{
va_list argp; // 变参数列表 argp, 具体定义与平台有关
int a;
va_start(argp,fmt); // 让argp 指向 &fmt, 具体实现与平台有关
//vsprintf 第3个参数是va_list 参数
//格式化输出, argp 会随fmt 中的%而自动递长,从而访问到先入栈的参数
a=vsprintf(str,fmt,argp);
va_end(argp);//停止使用可变参数, 可保持结构的完整性
return(a);
}
int main(void)
{
int i=35;/*定义变量*/
float f=12.4;
char s[4]="old";
vspf("%d,%f,%s\n",i,f,s);/*调用自定义函数,压栈了若干个参数*/
printf("%s ",str);/*输出字符串*/
return 0;
}
3点说明:
1. 可变参数函数. 传到函数堆栈中的参数不知道有多少个.
2. va_list 是什么类型?
我用gdb 在linux 下打印了一下:
(gdb) ptype va_list
type = struct typedef __va_list_tag __va_list_tag {
unsigned int gp_offset;
unsigned int fp_offset;
void *overflow_arg_area;
void *reg_save_area;
} [1]
3. argp 是如何变化的?
开始时的 argp
(gdb) print argp
$2 = {{
gp_offset = 0,
fp_offset = 0,
overflow_arg_area = 0x0,
reg_save_area = 0x0
}}
用fmt 初始化后的argp
(gdb) p argp
$3 = {{
gp_offset = 8,
fp_offset = 48,
overflow_arg_area = 0x7fffffffdcc0,
reg_save_area = 0x7fffffffdc00
}}
用vsprintf 使用过后的argp
(gdb) p argp
$6 = {{
gp_offset = 24,
fp_offset = 64,
overflow_arg_area = 0x7fffffffdcc0,
reg_save_area = 0x7fffffffdc00
}}
argp地址是比format 地址大的地址,都在堆栈中放着呢.
argp 到底从堆栈中拿多少参数,由format 中的内容%个数来决定.