快速业务通道

c/c++支持可变参数的函数

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-29
glist;
int buffing;
        int retval;

va_start(arglist, format); //arglist指向format后面的第一个参数

...//不关心其它代码
        retval = _output(stdout,format,arglist); //把format格式和参数传递给output函数

...//不关心其它代码
return(retval);
}

我们先模仿这个函数写一个:

#i nclude <stdio.h>
#i nclude <stdarg.h>

int mywrite(char *fmt, ...)
{
     va_list arglist;
     va_start(arglist, fmt);
     return printf(fmt,arglist);
}

void main()
{
int i=10, j=20;
char buf[] = "This is a test";
double f= 12.345;
mywrite("String: %s\nInt: %d, %d\nFloat :%4.2f\n", buf, i, j, f);
}

运行一下看看,哈,错误百出。仔细分析原因,根据宏的定义我们知道 arglist是一个指针,它指向第一个可变的参数,但是所有的参数都位于栈中,所以arglist指向栈中某个位置,通过arglist的值,我们可以直接查看栈里面的内容:

arglist -> 指向栈里面,内容包括

0067FD78 E0 FD 67 00 //指向字符串"This is a test"

0067FD7C 0A 00 00 00 //整数 i 的值

0067FD80 14 00 00 00 //整数 j 的值

0067FD84 71 3D 0A D7 //double 变量 f, 占用8个字节

0067FD88 A3 B0 28 40

0067FD8C 00 00 00 00

如果直接调用 printf(fmt, arglist); 仅仅是把arglist指针的值0067FD78入栈,然后把格式字符串入栈,相当于调用:

printf(fmt, 0067FD78);

自然这样的调用肯定会出现错误。

我们能不能逐个把参数提取出来,再传递给其它函数呢?先考虑一次性把所有参数传递进去的问题。

如果调用的是系统库函数,这种情况下是不可能的。因为提取参数是在运行态,而参数入栈是在编译的时候确定的。无法让编译器预知运行态的事情给出正确的参数入栈代码。而我们在运行态虽然可以提取每个参数,但是无法将参数一次性全部压栈,即使使用汇编代码实现起来也是很困难的,因为不单是一个简单的push代码就可以做到。

如果接受参数的函数也是我们自己写的,自然我们可以把arglist指针入栈,然后在函数中自己解析arglist指针里面的参数,逐个提取出来处理。但是这样做似乎没有什么意义,一方面,这个函数没有必要也做成可变参数函数,另一方面直接在第一个函数中解析参数,然后处理不是更简单么?

我们唯一可以做到的是,逐个解析参数,然后循环中调用其它可变参数函数,每次传递一个参数。这里又有一个问题,就是参数表中的不可变参数的传递问题,有些情况下不能简单的传递,以上面的例子为例, 通常我们解析参数的同时,还需要解析格式字符串:

#i nclude <windows.h>
#i nclude <stdio.h>
#i nclude <stdarg.h>

//测试一下这个,开个玩笑
void t(...)
{
printf("\n");
}

int mywrite(char *fmt, ...)
{
va_list arglist;
va_start(arglist, fmt);

char temp[255];
strcpy(temp, fmt); //Copy the Format string
char Format[255];

char *p = strchr(temp,''%'');
int i=0;
int iParam;
double fParam;
while(p != NULL)
{
   while((*p<''a'' || *p>''z'') && (*p!=0) ) p++;
   if(*p == 0)break;
   p++;

   //格式字符串
   int nChar = p - temp;
   strncpy(Format,temp, nChar);
   Format[nChar] = 0;
   //参数
   if(Format[nChar-1] != ''f'')
   {
    iParam = va_arg( arglist, int);
    printf(Format, iParam);
   }
   else
   {
    fParam = va_arg( arglist, double);
    printf(Format, fParam);
   }

   i++;
   if(*p ==

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号