• va_list ,va_start ,va_arg ,va_copy ,va_end ,vsprintf ,vsnprintf 详细解析


    1定义

    这些宏在stdarg.h,定义如下:

     1 #include <stdarg.h>  
     2 typedef char *va_list;
     3 #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
     4 #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一个可选参数地址
     5 #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数的值
     6 #define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效
     7 
     8 void va_start(va_list ap, last);     
     9 type va_arg(va_list ap, type);       
    10 void va_end(va_list ap);   
    11 void va_copy(va_list dest, va_list src);

    以上几个宏定义关键是_INTSIZEOF(n)的含义。

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

    含义是向上取整成 sizeof(int) 的整数倍,用来地址对齐。

    1)  数学整除的例子

    举个简单的数学整除运算例子

    如5/2=2, 7/2=3,再进行如下运算:

    (5/2)*2=4, (7/2)*3=6

    即可得到小于被除数的最大的除数的整数倍。

    2)字节对齐的含义:

    现在有以数据长度为L = 4M+m,如果按照M字节对齐, 对齐后需占用5个M,但实际长度记为4M+m。

     

    如上,蓝色一个格为M字节,红色为m字节,m < M。

    经过上述数学整除运算后L变成4M = (L/M) * M。

    但是与所需的5M 少了一个M。那怎么办呢?

    如果将原数据长度增加一格(L+M),再进行上述运算,即((L+M)/M) * M = 5M

    3)但是呢,会存在如下的问题

    假设数据长度为Y = 6M,刚好为一格长度M的整数倍。

    经过以上运算为:((Y+M)/M) * M = 7M,那如果不加M ,只加M-1呢?

    ((Y+M-1)/M) * M = 6M,对头,这样就完美了。

    4)言归正传,解释宏定义。

    (sizeof(n)+sizeof(int)-1) & (~(sizeof(int) - 1)) = _INTSIZEOF(n)

    ((Y+M-1)                        /M) * M                    = 6M

    &符号左边部分相当于(Y+M-1),右边&~(sizeof(int) - 1),对应/M*M。对二进制来说就是右移M位,再左移M位。因为右移会丢掉低位的,再次左移后相当于把低位清零了。

    若a为2的n次幂,那就是最高位为1,其余位即低位为n个0。

    a-1的二进制相反,低位n个1,最高位为0。再按位取反就是a,即(~(sizeof(int) - 1))。

    最后再按位与,就可以实现将A的低n位清零,即&(~(sizeof(int) - 1))。

    3 函数堆栈中的摆放

    在进程中,堆栈地址是从高到低分配的.当执行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的执行代码 ,堆栈地址不断递减。最后一个参数在列表中地址最高部分,第一个参数在列表地址的最低部分.参数在堆栈中的分布情况如下:

    最后一个参数

    倒数第二个参数

    ...

    第一个参数

    函数返回地址

    函数代码段

    void va_copy(va_list dest, va_list src);很简单,src copy到 dest,不在详述。

    4实例

    1)int型实例:

     1 #include <stdio.h>
     2 #include <stdarg.h>
     3 //int demo(int format, ...);
     4 int demo(int format, ...)
     5 {
     6   va_list ap;
     7   int n;
     8   va_start(ap, format);
     9   while(n != 0{
    10     n = va_arg(list, int);
    11    // if(n != 0){
    12       printf("%d
    ",n);
    13      // break;
    14    // }
    15     printf("para #%d is:%d ",sum,n);
    16   }
    17   va_end(ap);
    18   return 0;
    19 }
    20 void main()
    21 {
    22   demo(1,2,3,4,5,6,7,8,9,0);
    23 }

    编译执行结果:

     ./test

    para #0 is : 2

    para #0 is : 3

    para #0 is : 4

    para #0 is : 5

    para #0 is : 6

    para #0 is : 7

    para #0 is : 8

    para #0 is : 9

    para #0 is : 0

    2)char型实例:

     1 #include <stdio.h>
     2 #include <stdarg.h>
     3 //int demo(int format, ...);
     4 void demo(char *format, ...)
     5 {
     6   va_list list;
     7   va_start(list,format);
     8   char *ch;
     9   while(ch != ""){
    10     ch = va_arg(list, char *);
    11     //if(strcmp(ch,"") == 0){
    12      printf("%s
    ",ch);
    1314     //}
    15    printf("%s ",ch);
    16   }
    17   va_end(list);
    18 }
    19 int main()
    20 {
    21   demo ("test","this","is","a","test","");
    22   return 0;
    23 }

    编译执行结果:

     ./test

    para #0 is : this

    para #0 is : is

    para #0 is : a

    para #0 is : test

    para #0 is : 

    3)vsprintf ,vsnprintf的使用实例

     1 #include <stdio.h>
     2 #include <stdarg.h>
     3 char buffer1[80] 4 char buffer2[80];
     5 int demo (char *format, ...)
     6 {
     7   va_list ap;
     8   va_start(ap, format);
     9   vsfprintf(buffer1, format,ap);
    10   vsnprintf(buffer2, 17,format, ap);
    11   va_end(ap);
    12   printf("vsprintf:%s 
    ",buffer1);
    13   printf("vsnprintf:%s 
    ",buffer2);
    14   return 0;
    15 }
    16 int main()
    17 {
    18   int num = 30;
    19   float flat = 90.000000;
    20   char c_data [4]= "abc";
    21   demo ("%d %f %s",num,flat,c_data);
    22   printf("sizeof(int):%d,sizeof(float):%d,sizeof(string):%d 
    ",sizeof(int),sizeof(float),sizeof(string));
    23   return 0;
    24 }

    sizeof(int):4,sizeof(float):4,sizeof(string):4

    vsprintf :30 90.000000 abc

    vsnprintf:30 90.000000 abc

    行胜于言,自强不息。
  • 相关阅读:
    ‘Host’ is not allowed to connect to this mysql server
    centos7安装mysql
    further configuration avilable 不见了
    Dynamic Web Module 3.0 requires Java 1.6 or newer
    hadoop启动 datanode的live node为0
    ssh远程访问失败 Centos7
    Linux 下的各种环境安装
    Centos7 安装 python2.7
    安装scala
    Centos7 安装 jdk 1.8
  • 原文地址:https://www.cnblogs.com/xinghuo123/p/12862871.html
Copyright © 2020-2023  润新知