可变参数的使用

 

在ANSI C中,这些宏的定义位于stdarg.h中:

typedef char *va_list;

va_start宏,获取可变参数列表的第一个参数的地址(list是类型为va_list的指针,param1是可变参数最左边的参数):

#define va_start(list,param1)   ( list = (va_list)&param1+ sizeof(param1) )

va_arg宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(mode参数描述了当前参数的类型):

#define va_arg(list,mode)   ( (mode *) ( list += sizeof(mode) ) )[-1]

va_end宏,清空va_list可变参数列表:

#define va_end(list) ( list = (va_list)0 )

注:以上sizeof()只是为了说明工作原理,实际实现中,增加的字节数需保证为为int的整数倍

如:#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

为了理解这些宏的作用,我们必须先搞清楚:C语言中函数参数的内存布局。首先,函数参数是存储在栈中的,函数参数从右往左依次入栈。

以下面函数为讨论对象:

void test(char *para1,char *param2,char *param3, char *param4) { va_list list; ...... return; }

在linux中,栈由高地址往低地址生长,调用test函数时,其参数入栈情况如下:

 当调用va_start(list,param1) 时:list指针指向情况对应下图:

 

va_arg的使用举例:

 1 #include <stdio.h>
 2 #include <stdarg.h>
 3 #include <stdlib.h>
 4 #include <string.h>
 5 
 6 
 7 void var_test(char *format, ...)
 8 {
 9     va_list list;
10     va_start(list,format);    
11     char *ch;
12     while(1)
13     {
14          ch = va_arg(list, char *);
15          if(strcmp(ch,"") == 0)
16          {    
17                printf("\n");
18                break;
19          }
20          printf("%s ",ch);
21      }
22      va_end(list);
23 }
24  
25 int main()
26 {
27     var_test("test","this","is","a","test","");
28     return 0;
29 }

 

vsprintf的使用举例一:

 1 #include <stdarg.h>
 2 #include<stdio.h>
 3         
 4 char buffer[80];
 5 int vspf(char *fmt, ...)
 6 {
 7     va_list argptr;
 8     int cnt;
 9     va_start(argptr, fmt);
10     cnt = vsprintf(buffer, fmt, argptr);
11     va_end(argptr);
12     return(cnt);
13 }
14 
15 int main(void)
16 {
17     int inumber = 30;
18     float fnumber = 90.0;
19     char string[4] = "abc";
20     vspf("%d %f %s", inumber, fnumber, string);
21     printf("%s\n", buffer);
22     return 0;
23 }

 

vsprintf的使用举例二:

 1 #include <stdio.h>
 2 #include <stdarg.h>
 3 #include <stdlib.h>
 4 #include <string.h>
 5 
 6 int printf_ext(const char* fmt, ...)
 7 {    
 8     char outbuf[128] = {0};
 9     va_list list;
10     //1.将变参转化为字符串
11     va_start(list,fmt);
12     
13     vsprintf((char *)outbuf, fmt, list);
14     
15     va_end(list);
16     
17     //2. 打印字符串到串口
18     int i;
19     for (i=0; i< strlen((char *)outbuf); i++)
20     {
21         putc(outbuf[i]); 
22     }
23     return i;
24 }
25 
26 
27 int main()
28 {
29     printf_ext("test","this","is","a","test","");
30     return 0;
31 }

 

总结:

VA_LIST的用法( VA_LIST 是在C语言中解决变参问题的一组宏):
(1)首先在函数里定义一个VA_LIST型的变量,这个变量是指向参数的指针
(2)然后用VA_START宏初始化变量刚定义的VA_LIST变量,这个宏的第二个
参数是第一个可变参数的前一个参数,是一个固定的参数。(如在运行VA_START
(ap,v)以后,ap指向第一个可变参数在堆栈的地址。)
(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型。
(4)最后用VA_END宏结束可变参数的获取。然后你就可以在函数里使用第二个参数了。
如果函数有多个可变参数的,依次调用VA_ARG获取各个参数。

 

VA_ARG函数用于获取一个一个的参数。
vsprintf函数和vsnprintf函数将所有的参数按fmt格式化输出到,buff中。

 vsprintf() 中的 arg 参数位于数组中。数组的元素会被插入主字符串的百分比 (%) 符号处。该函数是逐步执行的。在第一个 % 符号中,插入 arg1,在第二个 % 符号处,插入 arg2,依此类推。

 

posted @ 2019-12-10 17:08  凌空a  阅读(338)  评论(0编辑  收藏  举报