1. C语言函数的调用方式 _cdecl 调用
_cdecl 是C Declaration的缩写(declaration,声明),表示C语言默认的函数调用方法:所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈所以在函数调用栈中, 越右边的参数在栈的越低端,既内存地址越大。
2.实现
函数如何实现不定参数:由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦,即使采用C++,如果参数个数不能确定,也很难采用函数重载。对这种情况,提出了指针参数来解决问题。
(1)va_list
定义了一个指针arg_ptr, 用于指示可选的参数.
(2)va_start(arg_ptr, argN)
使参数列表指针arg_ptr指向函数参数列表中的第一个可选参数,argN是位于第一个可选参数之前的固定参数,
或者说最后一个固定参数.如有一va 函数的声明是void va_test(char a, char b, char c, ...), 则它的固定参数依次是a,b,c, 最后一个固定参数argN为c, 因此就是va_start (arg_ptr, c).
(3)va_arg(arg_ptr, type)
返回参数列表中指针arg_ptr所指的参数, 返回类型为type. 并使指针arg_ptr指向参数列表中下一个参数.返回的是可选参数, 不包括固定参数.
(4)va_end(arg_ptr)
清空参数列表, 并置参数指针arg_ptr无效.
(注:va在这里是variable-argument(可变参数)的意思. 这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件)
过程:
调用va_start()后parg将指向第一个不固定的参数,在这个函数中也就是v2后面的参数。
接着调用va_parg():va_parg同样接受两个参数第一个参数是经过va_start()处理过后的parg指针。
第二个参数是期望不固定参数的类型,编译器无法确定可变参数的类型,但是必须这么做。
va_parg返回parg当前指向的那个可变的参数。并且每次调用都会更新这个指针,使得parg向下个参数移动;
最后调用va_end():va_end接受一个参数,parg,他会将parg重置为NULL;没用调用va_end函数将无法运行。
3.举例
(1)固定参数个数(2个)
#include <stdio.h> #include <stdlib.h> #include <stdarg.h> int print(const char *format, ...) { va_list args; const char *args1; va_start(args, format); args1 = va_arg(args,const char *); va_end(args); printf("format=%s args1=%s", format, args1); } int main() { print("11111", "22222"); }
运行结果:
format=11111 args1=22222
(2)多个参数(采用循环)
double average(double v1, double v2, ...){ va_list parg; //将parg指向第一个不固定的参数 va_start(parg, v2); double sum = 0.0; sum = v1 + v2; double value; int count = 2; //va_arg判断下一个不固定参数类型是否为double while((value = va_arg(parg, double)) != 0.0){ sum += value; ++count; } va_end(parg); return sum/count; }
4.注意
va_arg(ap,type)中的type绝对不能为以下类型:
——char、signed char、unsigned char
——short、unsigned short
——signed short、short int、signed short int、unsigned short int
——float
参考:
https://www.cnblogs.com/linhaostudy/p/6695422.html
https://blog.csdn.net/wabil/article/details/72800624?utm_source=blogxgwz0
https://blog.csdn.net/bristar_zon/article/details/48465021
https://blog.csdn.net/qq_25367755/article/details/50946574