printf函数是在串口信息打印中和串口命令行接口功能实现中经常用的函数。调用方式一般是这样子的printf("cmd =%s\r\rn", cmd_str),printf("vol=%dmV, current=%dmA.", vol,current)等方式。在字符串后面的输入的参数个数可变化,printf的这种参数就是变长参数。
变长参数的函数实现需要使用strarg.h头文件中定义的一个重要的宏,如下
typedef char *va_list
void va_start(va_list )
void va_end(va_list ap);
下面编写一个变长参数的函数来说明其原理。
void print_demo(char *form,...)
{
va_list argp;
int argno = 0;
int para;
/*argps获取输入第二个参数的指针*/
va_start(argp, form);
while(1)
{
/*按4字节字的方式取得输入变长参数的数值 para分别返回main函数中调用传入的字符串指针,a,b,c三个变量的值*/
para = va_arg(argp, int);
argno++;
/*这个循环中要根据输入的form中把指向的字符串中的数据的个数进行退出*/
if(argon > 4)
{
break;
}
}
va_end(argp);
}
int main(void)
{
unsigned char a = 1, b = 2, c = 3;
char *ss = "hello";
printf_demo("%s,%d,%d,%d,%s", s, a, b, c, s);
}
下面是程序仿真执行的结果:
在函数print_demo中的每个循环打印出来一个输入参数的值,即分别打印出来print_demo()函数中输入的字符串s的地址,a的值,b的值,c的值,字符串s的地址。
总结一下变长参数的实现原理,main函数中执行printf_demo("%s, %d,%d,%d,%s", s, a, b, c, s)时,程序第一个参数格式化字符串的指针赋值到寄存器R0, 第二个参数s赋值到寄存器R1, 第三个参数a赋值到寄存器R2, 第四个参数b赋值到寄存器R3,第五个参数c, 第六个参数s压入堆栈。
执行到printf_demo内部时,R0-R3压入堆栈中去,此时堆栈中保存了第一个参数格式化字体串指针,s,a,b,c,s这个五个数值。va_start(argp, form);这个语句读取到堆栈中的第二个参数的在内存中的指针。para = va_arg(argp, int);这个函数循环调用 取出来第二个参数到第五个参数的值。