• va_list、va_start、va_arg、va_end


    转载:https://www.cnblogs.com/bwangel23/p/4700496.html

    这几个函数和变量是针对可变参数函数的,什么是可变参数函数呢,最经典的莫过于printf和scanf,这两个函数的声明如下:

    1 int printf(const char *format, ...);
    2 int scanf(const char *format, ...);

    这两个函数声明中省略号(...)表示的就是任意个数的参数,可变参数函数就是输入的参数的个数是可变的,那么这个具体是怎么实现的呢?

      要了解这个是怎么实现,首先我们就要先理解一点,参数是如何传递给函数的。众所周知,函数的数据是存放于栈中的,那么给一个函数传递传递参数的过程就是将函数的参数从右向左逐次压栈,例如:

      func(int i, char c, doube d)

      这个函数传递参数的过程就是将d,c,i逐次压到函数的栈中,由于栈是从高地址向低地址扩展的,所以d的地址最高,i的地址最低。

      理解了函数传递参数的过程,再来说一下va_list的原理,通常,可变参数的代码是这么写的:

    1 void func(char *fmt, ...)
    2 {
    3      va_list ap;
    4 
    5      va_start(ap, fmt);
    6      va_arg(ap, int);
    7      va_end(va);      
    8 }

    这里ap其实就是一个指针,指向了参数的地址。

      va_start()所做的就是让ap指向函数的最后一个确定的参数(声明程序中是fmt)的下一个参数的地址。

      va_arg()所做的就是根据ap指向的地址,和第二个参数所确定的类型,将这个参数的中的数据提取出来,作为返回值,同时让ap指向下一个参数。

      va_end()所做的就是让ap这个指针指向0。

      关于这三个参数实现的宏可以参看下面的实现:

    1 // 使ap指向第一个可变参数的地址
    2 #define  va_start(ap,v)     ( ap = (va_list)&v + _INTSIZEOF(v) )
    3 
    4 // 使ap指向下一个可变参数,同时将目前ap所指向的参数提取出来并返回
    5 #define  va_arg(ap,t)       ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
    6 
    7 //  销毁ap 
    8 #define  va_end(ap)         ( ap = (va_list)0 )

    参考文章:

    1. http://wenku.baidu.com/view/ecb33901de80d4d8d15a4fe3.html

  • 相关阅读:
    超级详细Tcpdump 的用法
    Javascript网站繁简转换解决方案
    IIS6.0下创建用户隔离模式FTP站点
    如何开启IIS里的FTP主动模式(PASV模式)
    C#正则表达式小结
    ServU权限提升再提升记一次虚拟主机入侵
    Linux命令网络操作之ifconfig
    创建使用 Active Directory 模式隔离用户的新 FTP 站点
    远程控制电脑创建影子帐户(后门)
    Linux shell编程笔记总结
  • 原文地址:https://www.cnblogs.com/Toya/p/11046043.html
Copyright © 2020-2023  润新知