C语言可变参数va_list
#include<stdlib.h>#include<stdio.h>#include<stdarg.h>/*1.使用va_listva_startva_argva_end实现可变参数*/voidsimple_va_fun(inti,...){va_listarguments;intj=0;intk,m;va_start(arguments,i);j=va_arg(arguments,int);m=va_arg(arguments,int);va_end(arguments);printf("%d,%d,%d\n",i,j,m);}/*2.固定参数函数*/voidfixed_args_func(charx,inta,doubleb,char*c){//打印参数在栈中的地址printf("x=0x%p\n",&x);printf("a=0x%p\n",&a);printf("b=0x%p\n",&b);printf("c=0x%p\n",&c);}/*3.实现自己的可变参数,实则是按顺序从栈中取出参数的值*/voidvar_args_func(constchar*fmt,...){char*ap;ap=(char*)&fmt+sizeof(fmt);int*int_ap=(int*)ap;printf("first:%d\n",*int_ap);int_ap=int_ap+1;printf("second:%d\n",*int_ap);int_ap=int_ap+1;//stringstartindexchar*c_ptr=(char*)int_ap;char*str=(char*)*int_ap;printf("&int_ap=0x%p\n",int_ap);printf("&c_ptr=0x%p\n",c_ptr);printf("&str=0x%p\n",str);//栈里面存储的是指向字符串"helloworld的指针",即二级字符指针printf("third1:%s\n",str);printf("third2:%s\n",*(char**)int_ap);}//stdarg.h中提供的标准可变参数宏voidstd_vararg_func(constchar*fmt,...){va_listap;va_start(ap,fmt);printf("%d\n",va_arg(ap,int));printf("%f\n",va_arg(ap,double));printf("%s\n",va_arg(ap,char*));va_end(ap);}intmain(){//fixed_args_func('a',17,5.40,"helloworld");//char*p="xiongwei";//printf("%d\n",sizeof(p));var_args_func("%d%d%s\n",4,5,"helloworld");printf("--------------------------------------\n");std_vararg_func("%d%f%s\n",4,5.4,"helloworld");system("pause");return0;}
对比一下 std_vararg_func和var_args_func的实现,va_list似乎就是char*, va_start似乎就是((char*)&fmt) + sizeof(fmt),va_arg似乎就是得到下一个参数的首地址。没错,多数平台下stdarg.h中va_list, va_start和var_arg的实现就是类似这样的。一般stdarg.h会包含很多宏,看起来比较复杂。在有的系统中stdarg.h的实现依赖some special functions built into thethe compilation system to handle variable argument lists and stack allocations,多数其他系统的实现与下面很相似:(Visual C++ 6.0的实现较为清晰,因为windows上的应用程序只需要在windows平台间做移植即可,没有必要考虑太多的平台情况)。
output://
first:4
second : 5
& int_ap = 0x003EF968
& c_ptr = 0x003EF968
& str = 0x013780D4
third1 : helloworld
third2 : helloworld
--------------------------------------
4
5.400000
helloworld
实现Printf()函数:
#include"stdio.h"#include"stdlib.h"voidmyprintf(char*fmt,...)/*一个简单的类似于printf的实现,//参数必须都是int类型*/{char*pArg=NULL;/*等价于原来的va_list*/charc;pArg=(char*)&fmt;/*注意不要写成p=fmt!!因为这里要对//参数取址,而不是取值*/pArg+=sizeof(fmt);/*等价于原来的va_start*/do{c=*fmt;if(c!='%'){putchar(c);/*照原样输出字符*/}else{/*按格式字符输出数据*/switch(*++fmt){case'd':printf("%d",*((int*)pArg));break;case'x':printf("%#x",*((int*)pArg));break;default:break;}pArg+=sizeof(int);/*等价于原来的va_arg*/}++fmt;}while(*fmt!='\0');pArg=NULL;/*等价于va_end*/return;}intmain(intargc,char*argv[]){inti=1234;intj=5678;myprintf("thefirsttest:i=%d",i,j);myprintf("thesecendtest:i=%d;%x;j=%d;",i,0xabcd,j);system("pause");return(0);}
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。