如何自定义可变参数函数

在我们编写代码中,有时需要我们自定义可变参数函数,像库函数中有pirntf,ioctl都是可变参数函数,如果我们要实现自定义可变参数,一般要实现像int ioctl(int fd, unsigned long request, ...)这种功能的。下面讲解如何实现ioctl这个类型函数

1.通过分析printf函数:

1)typedef char *va_list;

2)#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) //计算n占用大小

3)#define va_start(ap,v)( ap = (va_list)&v + _INTSIZEOF(v) ) //获取第一个可变参数在栈地址(在栈中参数入参顺序为从右至左,栈底为高地址,栈顶为底地址,&v+_INTSIZEOF(v) ,这里&v是最后一个固定参数的起始地址,再加上其实际占用大小后,就得到了第一个可变参数的起始内存地址。所以我们运行va_start (ap, v)以后,ap指向第一个可变参数在的内存地址

4)#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

/*这个宏做了两个事情,

①用用户输入的类型名对参数地址进行强制类型转换,得到用户所需要的值

②计算出本参数的实际大小,将指针调到本参数的结尾,也就是下一个参数的首地址,以便后续处理。*/

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

2.模板:

void myioctl(int select,...)

{

va_list args;

va_start(args, select);//将args赋值为第一个可变参数地址

switch(select){

case 1:

//假设这个选项需要两个可变参

int i=va_arg(args,int);

char c=va_args(args,char);

......

va_end(args);

case 2:

.....

}

va_end(args);

}

3.举例子

#include<stdio.h>
#include<stdarg.h>//第一部分说明的那几个宏就在这个头文件实现的

#if 0
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
typedef char *va_list1;
#define va_start1(ap,v)( ap = (va_list1)&v + _INTSIZEOF(v) ) 
#define va_arg1(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end1(ap) ( ap = (va_list1)0 ) 

#endif
void myioctl(int select,...)
{
va_list args;
int i;
int c;
char* d;
va_start(args, select);
switch(select){
case 1:
i=va_arg(args,int);
c=va_arg(args,int);
printf("test:i=%d,c=%d\n",i,c);
break;
case 2:
i=va_arg(args,int);
d=va_arg(args,char*);
printf("test:i=%d,c=%s\n",i,d);
break;
}
va_end(args);
return;
}
int main()
{
int a=0x34,b=0x23;
char* string="haode";
myioctl(0x1,a,b);
myioctl(0x2,a,string);
return 0;
}

疑问:很奇怪,我不用库里自带的va_start,va_args(即不用头文件stdarg.h),而是自定义上面的,居然不行,不知道怎么回事。

猜你喜欢

转载自blog.csdn.net/u012681014/article/details/70177527
今日推荐