Printf实现多参的原理

来源:互联网 发布:心理咨询 成都 知乎 编辑:程序博客网 时间:2024/06/18 05:29


一直以来,Printf实现多参的原理,是C面试时的重点问题。现在就来介绍一下其实现的原理。

其原型为int printf( const char *format,... ); 

函数的传递的参数是存储到栈区的,因而printf的参数也遵循从又往左开始进行压栈。

int i = 0;

printf ("%d, %d, %d",i + 3, i + 2, i + 1);

首先最右边i + 1 为1入栈,栈的地址又下往上是高到低。






1

然后中间i + 2为2入栈





21

最后第一个i + 1入栈




321最后的输出是使用出栈的形式。所以输出是3,2,1。

那么为什么可以找到这些参数,而且又是为什么会知道传入的参数有几个呢?

在这里我们需要认识到va_list这个数据类型。

VA_LIST的用法:      
       (1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针
       (2)然后用VA_START宏初始化变量刚定义的VA_LIST变量,这个宏的第二个参数是第一个可变参数的前一个参数,是一个固定的参数。
       (3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型。
       (4)最后用VA_END宏结束可变参数的获取。然后你就可以在函数里使用第二个参数了。如果函数有多个可变参数的,依次调用VA_ARG获取各个参数。

下面我们以一个列子来说明:

int Sum( int first, ... ) //变参数函数,C++里也有 {     int count=0,i=0,sum=0;     va_list maker; //va_list 类型数据可以保存函数的所有参数,做为一个列表一样保存     va_start(maker,first); //设置列表的起始位置     while(count <= first)     {         sum+=i;         count++;         i=va_arg(maker,int);//返回maker列表的当前值,并指向列表的下一个位置     }    va_end(maker);    return sum; } 

上面是一个求和函数,第一个参数为后面求个参数的个数。
首先,va_start可以根据第一个参数first确定函数传入参数在栈中的位置,(知道一个变量名,我们可以确定其存储的地址,这样就可以知道该系列参数入栈的首地址)。然后使用va_arg依次取出后续参数。
printf的函数原型为:int printf( const char *format,... ); 
可以看出其一个参数为const char*类型。如:“%d,%d,%d",我们可以通过分析这一串有约定的字符串,得出后续的参数的个数,以及其每一个参数的数据类型。通过va_arg(va_list,data type如int、double等)取出数据。
这样就可以确定输入的参数是那些了。
注:调用va_end使va_list的指针复原,并清空栈。

原创粉丝点击