C语⾔arg参数读取⽂件,C语⾔可变参数函数详解⽰例先看代码
代码如下:
printf(“hello,world!”);其参数个数为1个。
printf(“a=%d,b=%s,c=%c”,a,b,c);其参数个数为4个。
如何编写可变参数函数呢?我们⾸先来看看printf函数原型是如何定义的。
在linux下,输⼊man 3 printf,可以看到prinf函数原型如下:
代码如下:
SYNOPSIS
#include
int printf(const char *format, ...);
后⾯的三个点...表⽰printf参数个数是不定的.
如何实现可变参数函数?
2. 编写可变函数准备
为了编写可变参数函数,我们通常需要⽤到头⽂件下定义的以下函数:
代码如下:
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
其中:
va_list是⽤于存放参数列表的数据结构。
va_start函数根据初始化last来初始化参数列表。
va_arg函数⽤于从参数列表中取出⼀个参数,参数类型由type指定。
va_copy函数⽤于复制参数列表。
va_end函数执⾏清理参数列表的⼯作。
上述函数通常⽤宏来实现,例如标准ANSI形式下,这些宏的定义是:
代码如下:
typedef char * va_list; //字符串指针
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
使⽤宏_INTSIZEOF是为了按照整数字节对齐指针,因为c调⽤协议下⾯,参数⼊栈都是整数字节(指针或者值)。
函数官⽅说明,如果你看到英⽂就烦,可以⾃⾏忽略以下说明。
va_start()
The va_start() macro initializes ap for subsequent use by va_arg() and
va_end(), and must be called first.
The argument last is the name of the last argument before the variable argument list, that is, the last argument of which the calling function knows the type.
Because the address of this argument may be used in the va_start() macro, it should not be declared as a register variable, or as a func‐
tion or an array type.
va_arg()
The va_arg() macro expands to an expression that has the type and value of the next argument in the call. The argument ap is the va_list ap initialized by va_start(). Each call to va_arg() modifies ap so that
the next call returns the next argument. The argument type is a type name specified so that the type of a pointer to an object that has the specified type can be obtained simply by adding a * to type.
The first use of the va_arg() macro after that of the va_start() macro returns the argument after last. Successive invocations return the values of the remaining arguments.
If there is no next argument, or if type is not compatible with the
type of the actual next argument (as promoted according to the default argument promotions), random errors will occur.
If ap is passed to a function that uses va_arg(ap,type) then the value
of ap is undefined after the return of that function.
va_end()
Each invocation of va_start() must be matched by a corresponding invo‐cation of va_end() in the same function. After the call va_end(ap) the variable ap is undefined. Multiple traversals of the list, each brack‐
eted by va_start() and va_end() are possible. va_end() may be a macro
or a function.
GNU给出的⼀个实例:
代码如下:
#include
#include
void
sizeof 指针foo(char *fmt, ...)
{
va_list ap;
int d;
char c, *s;
va_start(ap, fmt);
while (*fmt)
switch (*fmt++) {
case 's': /* string */
s = va_arg(ap, char *);
printf("string %sn", s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("int %dn", d);
break;
case 'c': /* char */
/* need a cast here since va_arg only takes fully promoted types */
c = (char) va_arg(ap, int);
printf("char %cn", c);
break;
}
va_end(ap);
}
说明:
va_start(ap, fmt);⽤于根据fmt初始化可变参数列表。
va_arg(ap, char *);⽤于从参数列表中取出⼀个参数,其中的char *⽤于指定所取的参数的类型为字符串。每次调⽤va_arg后,参数列表ap都会被更改,以使得下次调⽤时能得到下⼀个参数。
va_end(ap);⽤于对参数列表进⾏⼀些清理⼯作。调⽤完va_end后,ap便不再有效。
以上程序给了我们⼀个实现printf函数的是思路,即:通过调⽤va_start函数,来得到参数列表,然后我们⼀个个取出参数来进⾏输出即可。
3.实例
例如:对于printf(“a=%d,b=%s,c=%c”,a,b,c)语句;fmt的值为a=%d,b=%s,c=%c,调⽤va_start函数将参数a,b,c存⼊了ap中。注意到:fmt中的%为特殊字符,紧跟%后的参数指明了参数类型.
因此我们的简易printf函数如下:
代码如下:
#include
#include
void
myprintf(char *fmt, ...)
{
va_list ap;
int d;
double f;
char c;
char *s;
char flag;
va_start(ap,fmt);
while (*fmt){
flag=*fmt++;
if(flag!='%'){
putchar(flag);
continue;
}
flag=*fmt++;//记得后移⼀位
switch (flag)
{
case 's':
s=va_arg(ap,char*);
printf("%s",s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("%d", d);
break;
case 'f': /* double*/
d = va_arg(ap,double);
printf("%d", d);
break;
case 'c': /* char*/
c = (char)va_arg(ap,int);
printf("%c", c);
break;
default:
putchar(flag);
break;
}
}
va_end(ap);
}
int main(){
char str[10]="linuxcode";
int i=1024;
double f=3.1415926;
char c='V';
myprintf("string is:%s,int is:%d,double is:%f,char is :%c",str,i,f,c);
}
从上⾯我们可以知道可变参数函数的编写,必须要传⼊⼀个参数fmt,⽤来告诉我们的函数怎样去确定参数的个数。我们的可变参数函数是通过⾃⼰解析这个参数来确定函数参数个数的。
⽐如,我们编写⼀个求和函数,其函数实现如下:
代码如下:
int sum(int cnt,...){
int sum=0;
int i;
va_list ap;
va_start(ap,cnt);
for(i=0;i
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论