C语言不定参数
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C语⾔不定参数
最近,遇到⼀个c语⾔的不定参数问题。
其实,对于c语⾔的不定参数问题,只需要三个函数就可以搞定了。
这三个函数的头⽂件是
<stdarg.h>,其实下⾯的三个函数都是⼀个宏定义(macro)。
这三个函数是:
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
如果需要进⾏其他的⼀些操作,可以查看⼀下man⼿册进⾏查询。
在这三个函数解释之前,先看⼀个变量va_list,这个变量的类型是什么呢?通过查看内核源代码,⼀直追踪下去,才发现它的类型是void *类型的。
对于va_start(va_list ap, last)函数,这个函数是⽤来初始化指针变量ap(va_list类型)的,以后处理参数就是默认从ap处开始处理。
last⼀般为char *传过来参数列表的第⼀个参数。
对于va_arg(va_list ap, type)函数来说,就是将ap指针按照type类型向后移动,然后取出ap指针所指的那个参数。
对于va_end(va_list ap)⼀般和va_start(va_list ap, last)配套使⽤,做⼀些善后处理的事情。
这⾥有⼀个问题,当我们取参数的时候,如何判断我们要取的参数已经取完了?开始我是这么想的,通过va_arg的返回值进⾏判断,通过查阅资料,都是这么说的,看来我的猜想是对的。
当我把程序写出来进⾏测试的时候,发现不是这样的:
#include <stdio.h>
#include <stdarg.h>
int sum(const int , ...);
int main(void)
{
printf("The result is:%d/n", sum(10, 9, 8));
return 0;
}
int sum(const int first, ...)
{
va_list argp;
int sum = 0;
int tmp;
va_start(argp, first);
sum += first;
printf("%d/n", first);
while((tmp = va_arg(argp, int)) != 0) {
printf("%d/n", tmp);
sum += tmp;
}
va_end(argp);
return sum;
}
这个程序的运⾏结果是:
10
9
8
6676468
134513824
The result is:141190319
这个结果说明,通过va_arg的返回值进⾏参数是否取完来判断是有问题的。
会不会是通过argp的值来判断的呢?让我们来做个测试:
#include <stdio.h>
#include <stdarg.h>
int sum(const int , ...);
int main(void)
{
printf("The result is:%d/n", sum(10, 9, 8));
return 0;
}
int sum(const int first, ...)
{
va_list argp;
int sum = 0;
int tmp;
va_start(argp, first);
sum += first;
printf("%d/n", first);
while(argp) {
tmp = va_arg(argp, int);
printf("%d/n", tmp);
sum += tmp;
}
va_end(argp);
return sum;
}
这个程序的执⾏结果出乎我的意料,出现了段错误。
⾄于如何修改这个程序把不定参数取出来,我还是没有找到解决⽅法。
后来,我想到了printf()函数,我查看了它的源代码,其中主要是调⽤了vsprintf()函数,⾄于为什么调⽤vsprintf()函数,我想可能是为了实现类似于fprintf()之类的函数调⽤的⽅便,这样也提⾼了函数的利⽤率。
printf()函数的主要代码:
328 va_start(args, fmt);
329 n = vsprintf(sprint_buf, fmt, args);
330 va_end(args);
我继续查看了vsprintf()函数,结果发现,在这个函数当中,它好像是通过判断字符串当中“%”号的多少来决定后⾯参数的个数的。
想到这⾥,我断定,在想调⽤不定参数这样的函数的时候,其实是需要指出参数的个数的,只是是通过间接的⽅式。
⽐如我们最熟悉的printf()函数,其实我们在第⼀个参数当中,通过%号已经指出了参数的个数,不是吗?
想到这⾥,我想到了之前看到man⼿册中给出的例⼦为什么是这样的:
#include <stdio.h>
#include <stdarg.h>
void
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 %s/n", s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("int %d/n", 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 %c/n", c);
break;
}
va_end(ap);
}
这⾥的话,不是就通过第⼀个参数指定之后才读取的吗?其实我觉得是间接的告诉了参数的个数。
通过上⾯的分析,下⾯做了⼀个简单的不定参数的应⽤。
问题描述:给定⼀些字符串,求出它们的最长开始字串。
实验代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
void fun(char *fmt, ...);
int main()
{
fun("sss", "fanabcd", "fanfanfanfan", "fanyyyyyyyyyyyy");//sss 表⽰了不定参数的个数
return 0;
}
void fun(char *fmt, ...)
{
va_list argp;
char * str, res[20] = {0};
int i;
va_start(argp, fmt);
if(*fmt == 's') {
str = va_arg(argp, char *);
strcpy(res, str);
}
fmt++;
while(*fmt) {
if(*fmt++ == 's') {
str = va_arg(argp, char *);
i = 0;
while(res[i] != '/0') {
if(res[i] != str[i]) {
res[i] = 0;
break;
}
i++;
}
}
}
va_end(argp);
printf("The result is:%s/n", res);
}
程序的执⾏结果是:
The result is:fan
通过这样的折腾,就把c语⾔的不定参数简单地应⽤起来了。