可变参数函数(一)
一个函数可以接受不定数的参数个数,这就是可变参数函数,比较常见的比如printf(),scanf();
printf(const char* format,…); printf(“%d”,i); printf(“%s”,s); printf(“the number is %d,stirng is :%s”,i,s);
变量参数函数的简单实现:
#include<stdio.h> #include<stdarg.h> int simple(int num,...) { int i,result = 0; va_list vl; va_start(vl,num); printf("num:%d, vl:%d\n",num,*vl); for(i = 0; i < num - 1 ; i++) { result = va_arg(vl,int); printf("in for result:%d ,*vl:%d\n",result,*vl); } va_end(vl); return result; } int main() { int sum = simple(5,1,2,3,4,5); if(0 == sum) { printf("simple failed\n"); } else { printf("simple success! sum = %d\n",sum); } return 0; }
结果如下:
exbot@ubuntu:~/wangqinghe/DeBug/20190702$ ./VA
num:5, vl:1020625376
in for result:1 ,*vl:1020625376
in for result:2 ,*vl:1020625376
in for result:3 ,*vl:1020625376
in for result:4 ,*vl:1020625376
simple success! sum = 4
sum.c #include<stdio.h> #include<stdlib.h> #include<stdarg.h> double add(int n,...) { //printf("add...\n"); int i = 0; double sum = 0; va_list argptr; va_start(argptr,n); //初始化argptr for(i = 0 ; i < n; i++) ////对每个可选参数,读取类型为int的参数 { sum += va_arg(argptr,int); //累加到sum中 } va_end(argptr); printf("add_sum = %f\n",sum); return sum; } int main(int argc,char **argv) { double sum = 0; int *p = malloc(argc * sizeof(int)); int i; for(i = 1; i < argc; i++) { p[i] = atoi(argv[i]); printf("p[%d] = %d\n",i,p[i]); } sum = add(argc,p[1]); printf("sum = %f\n",sum); sum = add(argc,p[1],p[2]); printf("sum = %f\n",sum); sum = add(argc,p[1],p[2],p[3]); printf("sum = %f\n",sum); free(p); return 0; }
输出结果;
exbot@ubuntu:~/wangqinghe/DeBug/20190702$ ./sum 10 20 30
p[1] = 10
p[2] = 20
p[3] = 30
add_sum = 239745405.000000
sum = 239745405.000000
add_sum = 56.000000
sum = 56.000000
add_sum = 69.000000
sum = 69.000000
相关函数介绍:
可变函数列表的实现由几个宏组成的,在文件#include<stdarg.h>中。
va_list 定义某个变量,内核的定义如下:
typedef char *va_list; //字符指针类型
va_start(ap,type) 开始获取可变参数列表中第一个参数(…里面的第一个),也就是跳过第一个参数。(所以以上的第一个输出是个随机值)。
#ifndef __sparc__ #define va_start(AP, LASTARG) \ (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))//ap指向下一个参数,lastarg不变 #else #define va_start(AP, LASTARG) \ (__builtin_saveregs (), \ AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG))) //跳过下第一个参数,指向第二个参数内存地址 #endif //对type向上取整 取int的整 4,然后乘上int整型4的倍数 #define __va_rounded_size(TYPE) \ (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
Va_arg(args,int)循环获取可变参数列表中的参数,args指向下一个参数地址,返回的是当前参数地址。
// first=va_arg(args,int) #define va_arg(AP, TYPE) \//ap指向下一个类型的参数 (AP += __va_rounded_size (TYPE), \//返回ap - sizeof(type)参数,即前一个参数 *((TYPE *) (AP - __va_rounded_size (TYPE)))) //对type向上取整 取int的整 4,然后乘上int整型4的倍数 #define __va_rounded_size(TYPE) \ (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
最后一个va_end(ap)结束标志,在程序中只是作为一个可变参数列表的结束标识,在stdarg.h中仅仅定义了一下,没有实现代码部分。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)