vsnprintf的使用以及c可变参数的传递机制

int vsnprintf (char * s, size_t n, const char * format, va_list arg );
cplusplus.com给出的解释是:Write formatted data from variable argument list to sized buffer
意思是把格式化的字符串format的最多n位字符写入缓冲区s中,format的参数列表为arg
其返回一个整型数ret,当且仅当ret非负,且ret小于n,表示函数运行成功,把ret个字符写入了缓冲区s
其余情况都视为函数运行失败。
以下是其例子
 1 /* vsnprintf example */
 2 #include <stdio.h>
 3 #include <stdarg.h>
 4 
 5 void PrintFError ( const char * format, ... )
 6 {
 7   char buffer[256];
 8   va_list args;
 9   va_start (args, format);
10   vsnprintf (buffer,256,format, args);
11   perror (buffer);
12   va_end (args);
13 }
14 
15 int main ()
16 {
17    FILE * pFile;
18    char szFileName[]="myfile.txt";
19 
20    pFile = fopen (szFileName,"r");
21    if (pFile == NULL)
22      PrintFError ("Error opening '%s'",szFileName);
23    else
24    {
25      // file successfully open
26      fclose (pFile);
27    }
28    return 0;
29 }
vsnprintf的示例

 

在例子中,我们可以看到PrintFError函数用于输出错误信息,其函数声明是这样子的

void PrintFError ( const char * format, ... )
这是一个可变参数的函数,同样,最常用的可变参数函数一定是
int printf ( const char * format, ... );

   可变参数可表示为 ...

   先来看看以下几个宏,在头文件stdarg.h中 (由于硬件平台和编译器的不同,这些宏的定义会有少许差异)

#define _INTSIZEOF(n)   ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) 
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )           //第一个可选参数地址
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址
#define va_end(ap)    ( ap = (va_list)0 )                            // 将指针置为无效

va_list 这是一个用于操作可变参数的类

利用va_start va_arg va_end,可以把所有可变参数取出。

用va_start(ap, v)获取第一个可选参数的地址, 所以v应该是最后一个非可变参数的地址

用va_arg(ap, t)获取下一个va_arg, t是该参数的类型

用va_end(ap) 来使ap变为NULL,结束可变参数操作

以下是代码示例

 1 /* va_start example */
 2 #include <stdio.h>      /* printf */
 3 #include <stdarg.h>     /* va_list, va_start, va_arg, va_end */
 4 
 5 void PrintFloats (int n, ...)
 6 {
 7   int i;
 8   double val;
 9   printf ("Printing floats:");
10   va_list vl;
11   va_start(vl,n);
12   for (i=0;i<n;i++)
13   {
14     val=va_arg(vl,double);
15     printf (" [%.2f]",val);
16   }
17   va_end(vl);
18   printf ("\n");
19 }
20 
21 int main ()
22 {
23   PrintFloats (3,3.14159,2.71828,1.41421);
24   return 0;
25 }
可变参数函数

 以下是图例

高地址|-----------------------------| 
            |函数返回地址 | 
            |-----------------------------| 
            |....... | 

            |-----------------------------|   <--va_arg后ap指向
            |第n个参数(第一个可变参数) | 
            |-----------------------------|   <--va_start后ap指向 
            |第n-1个参数(最后一个固定参数)| 
低地址|-----------------------------|       <-- &v 
          图(1) 

ps: 由于可变参数的类型和个数是不确定的,使用这些宏的时候不得不很小心地指定变量类型。

我们可以人为约定一种格式,使得程序可以准确地获取到变量。

最后一个固定参数可以定为整型,表示后面有多少组可变参数

每组可变参数由一个整型和一个任意类型的参数组成 ,表示:{类型,值}

这样就可以很容易地解决可变参数类型和个数不确定的问题了。

示例代码:

 1 #include <stdio.h>
 2 #include <stdarg.h>  // 可变参数需要的头文件
 3 
 4 #define ARG_DOUBLE 1
 5 #define ARG_INT 2
 6 #define ARG_CHARS 3
 7 
 8 // 可变参数函数va_print
 9 void va_print(int n, ...)
10 {
11     int cnt = 0; // 计数器
12     va_list ap;  
13     va_start(ap, n); // 将ap指向最后一个固定参数n的下一个地址
14     while(cnt < n)
15     {
16         // 用arg1记录arg2的类型,并按类型获取arg2
17         int arg1 = va_arg(ap, int);  
18         if (ARG_DOUBLE == arg1)
19         {
20             double arg2 = va_arg(ap, double);
21             printf("arg%d : %lf\n", cnt+1, arg2);
22         }
23         else if (ARG_INT == arg1)
24         {
25             int arg2 = va_arg(ap, int);
26             printf("arg%d : %d\n", cnt+1, arg2);
27         }
28         else if (ARG_CHARS == arg1)
29         {
30             char* arg2 = va_arg(ap, char*);
31             printf("arg%d : %s\n", cnt+1, arg2);
32         }
33         cnt++;
34     }
35     va_end(ap); // 把ap指向NULL
36     printf("this is a line...............\n");
37 }
38 
39 int main()
40 {
41     //调用va_print
42     va_print(3, ARG_DOUBLE, 0.01, ARG_INT, 0, ARG_CHARS, "abcde");
43 }
可变参数使用示例

 

参考网站:

http://blog.csdn.net/edonlii/article/details/8497704

http://www.cppblog.com/qiujian5628/archive/2008/01/21/41562.html

http://www.cplusplus.com/

 

posted on 2014-05-13 21:42  Elenno  阅读(978)  评论(0编辑  收藏  举报

导航