zoukankan      html  css  js  c++  java
  • 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 ("
    ");
    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
    ", cnt+1, arg2);
    22         }
    23         else if (ARG_INT == arg1)
    24         {
    25             int arg2 = va_arg(ap, int);
    26             printf("arg%d : %d
    ", cnt+1, arg2);
    27         }
    28         else if (ARG_CHARS == arg1)
    29         {
    30             char* arg2 = va_arg(ap, char*);
    31             printf("arg%d : %s
    ", cnt+1, arg2);
    32         }
    33         cnt++;
    34     }
    35     va_end(ap); // 把ap指向NULL
    36     printf("this is a line...............
    ");
    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/

     
  • 相关阅读:
    [no_code][Beta]事后分析
    [no_code][Beta]项目展示博客
    [no_code][Beta]测试报告
    [no_code][Beta]发布声明报告
    [no code][scrum meeting] Beta 12
    [no code][scrum meeting] Beta 11
    [no code][scrum meeting] Beta 10
    [no code][scrum meeting] Beta 9
    [no code][scrum meeting] Beta 8
    [no_code][Beta] 中期组内总结
  • 原文地址:https://www.cnblogs.com/elenno/p/va.html
Copyright © 2011-2022 走看看