C可变参数

来源:互联网 发布:linux创建新目录命令 编辑:程序博客网 时间:2024/04/25 05:58

一. printf函数的实现原理

1.从后向前扫描,C/C++的函数参数是通过压入堆栈的方式来给函数传参数的(堆栈是一种先进后出的数据结构),最先压入的参数最后出来。
2.栈是从内存的高地址向低地址生长的,控制生长的就是堆栈指针了,最先压入的参数是在最上面,就是说在所有参数的最后面,最后压入的参数在最下面,结构上看起来是第一个,所以最后压入的参数总是能够被函数找到,因为它就在堆栈指针的上方。
所以printf首先找到的就是字符指针”%d%s”,比如,printf(“%d%s”,10,”sacd”);
这里写图片描述

二、可变参数的设计


  • 标准头文件<stdarg.h>

    定义了数据类型va_list,三个宏:va_start, va_arg, va_endva-list是一个char类型的指针,当被调用函数使用一个可变参数时,它声明一个类型为va-list的变量,该变量用来指向va-arg和va-end所需信息的位置

    typedef char *  va_list;    void va_start(va-list ap,lastfix);

ap:指向被传递给函数的可变参数表中的第一个参数,可以由它得到第一个参数内存的地址;
astfix:是传递给被调用函数的最后一个固定参数的标识符

  • va_start在C中的源码
#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )   //得到可变参数中第一个参数的首地址

type va_arg(va_list ap,type)也是一个宏,返回ap所指对象的值,修改参数指针ap使其增加以指向表中下一个参数;
va_arg的第二个参数提供了修改参数指针所必需的信息。在第一次使用va-arg时,它返回可变参数表中的第一个参数,后续的调用都返回表中的下一个参数,下面给出va_arg在C中的源码

#define va_arg(ap,type)    ( *(type *)((ap += _INTSIZEOF(type)) - _INTSIZEOF(type)) )    //将参数转换成需要的类型,并使ap指向下一个参数

注意第二个参数所用类型名应与传递到堆栈的参数的字节数对应,以保证能对不同类型的可变参数进行正确地寻址,比如实参依次为char型、char * 型、int型和float型时,在va-arg中它们的类型则应分别为int、char *、int和double.

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

举例说明:比如我们要求可变参数的和 int sum(int n,…)


1.首先要用宏对变量n进行初始化: va_start(vap,n);相当于 char vap = (char )&n + sizeof(int); 此时vap就指向n后面可变参数中的第一个参数

2.通过va_arg访问函数调用的各个实际参数,宏va_arg的类型特征为 va_arg(va_list vap, 类型名) va_arg不仅返回一个实际参数的值,完成某种更新操作,指向下一个参数的地址 v = va_arg(vap, int);
3.函数在退出之前,必须有一个结束动作。va_end void va_end(va_list vap);

参考资料: http://blog.csdn.net/hackbuteer1/article/details/7558979

0 0
原创粉丝点击