c语言 神奇的可变参数

关于sprintf,printf,这些函数,参数都是不固定的。而这样编程方式,也可以自己来搞定。c语言提供了几个宏就是做这个的。

va_list //一个很特殊的类型
type va_arg(va_list ap, type);
void va_start(va_list ap, last_arg);
void va_end(va_list ap);
void va_copy(va_list dest,va_list src);

这个va_list是一个完整的对象类型,适用于保存宏va_start,va_copy,va_arg和va_end所需的信息。

如果创建了一个va_list实例,传递给另一个函数,并通过该函数中的va_arg使用,则在调用函数中的任何后续使用都应该在调用va_end之前进行。

先看一个最简单的例子

#include <stdarg.h>
int Sum(int n, ...) {
	int i;
	int sum = 0;
	va_list mark;
	//va_list sub;
	
	va_start(mark, n);
	//va_copy(sub, mark);

	printf("n is %d\n", n);
	for (i = 0; i < n; ++i) {
		int tmp = va_arg(mark, int);
		//int tmp = va_arg(sub, int);
		sum += tmp;
		printf("val is %d\n", tmp);
	}
	va_end(mark);
	//va_end(sub);
	return sum;
}
int main() {
	int ret = Sum(5, 1, 2, 3, 4, 5);
	printf("\nsum is %d", ret);
	return 0;
}

可以简单理解va_start就是初始化,其第二个参数 last_arg在本例中可发现就是“n”,这个就是最后接收到的固定参数。为什么是最后接收到,是因为参数的压栈顺序,这个可自行google。

另外,我把va_copy的注释起来了,这个就是简单的拷贝。然后va_end看头文件就是定义为((void)(ap = (va_list)0))。也没什么好说的。

但是这样简单应用看起来也没啥用。下面的写法便会让人一目了然。

#include <stdio.h>
#include <stdarg.h>

char buffer[80];
int vspfunc(char* format, ...)
{
	va_list aptr;
	int ret;

	va_start(aptr, format);
	ret = vsprintf(buffer, format, aptr);
	printf("test1 %d\n", va_arg(aptr, int));
	printf("test2 %d\n", va_arg(aptr, int));
	printf("test3 %s\n", va_arg(aptr, char*));
	va_end(aptr);

	return(ret);
}

int main()
{
	int i = 5;
	int f = 27;
	char str[50] = "tutoriasyiibai.com";

	vspfunc("%d %d %s", i, f, str);
	printf("\n\n%s", buffer);

	return(0);
}

这就好像sprintf一样,使用vsprintf,我把这3部分黏贴到了buffer中。这对于像做日志系统等的还是有些用处的。

需要注意的是,我在vspfunc里三个printf,我本来看va_arg菜鸟驿站的解释(这个宏检索函数参数列表中类型为 type 的下一个参数),还以为顺序不重要,对这个例子,因为只有一个char*,所以怎么都可以打印出来,而int有两个,所以那俩int才有顺序。

试了下发现,先打印char*还是会报错的。还是要按照顺序来的。看了下头文件的定义,发现原来并没有搞什么缓存之类的,所以我这个例子,char*和int所占空间的不同,由于读取顺序的错误必然出错。还是不能想当然啊。

发布了19 篇原创文章 · 获赞 1 · 访问量 927

猜你喜欢

转载自blog.csdn.net/tjw316248269/article/details/104801091