C语言变参函数的原理与应用

变参函数

变参函数其实并不罕见,在初学者的的 helloworld 程序中就用到了变参函数 printf() ,在之后的学习当中,scanf() 又是另一个常见的变参函数。
这些函数有以下共同特点:

  • 可以输入一个到任意多个参数
  • 从第二个参数开始,参数的类型不固定
  • 可以从第一个参数推测应该输入的参数类型及个数

实现原理

在函数调用过程中,相应内存的栈空间会增长,这时函数参数会被压到栈中。在普通函数执行时,函数根据参数列表得知栈内的参数类型以及个数,计算出相应参数的地址 和 占用空间大小,从而从栈中获取各个形参变量。
变参函数也要知道实际传入参数的类型以及个数,通过变参列表的起始位置,计算出所有参数的地址以及长度,这样成功读取到所有传入的参数。
C语言的变参函数需要传入至少一个在变参列表之外的固定参数,而这个固定参数所起到的作用就是 告诉函数变参列表的类型及个数 和 定位变参列表的位置。

实现方法

  • 包含 stdarg.h 头文件
  • 参数列表为固定参数+可变参数的形式,可变参数在声明和定义中用省略号,即三个点号(…)表示。
  • 函数定义中创建一个 va_list 类型变量。
  • 使用最后一个固定参数和 va_start 宏来初始化 va_list 变量为一个参数列表。
  • 使用 va_arg 宏和 va_list 变量来访问参数列表中的每个项。
  • 最后,使用宏 va_end 来清理赋予 va_list 变量的内存。

代码示例

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
int my_printf(const char *format, ...)
{
    int length = strlen(format);
    va_list valist;//创建valist变量
    va_start(valist,format);//使用...前一个参数初始化valist
    for (int i = 0; i < length-1; i++){
        if (format[i] == '%'){
            switch (format[i+1]){
                case 'c':
                    printf("char: %c\n", va_arg(valist,int));//char 会被转换成 int 类型来存储
                    break;
                case 'd':
                    printf("int: %d\n", va_arg(valist,int));
                    break;
                case 'f':
                    printf("float: %f\n",va_arg(valist,double));//float 会被转换成 double 类型来存储
                    break;
                case 's':
                    printf("char*: %s\n", va_arg(valist,char*));
                    break;
                case 'l':
                    switch(format[i+2]){
                        case 'f':
                            printf("double: %lf\n", va_arg(valist,double));
                            break;
                        case 'd':
                            printf("long: %ld\n", va_arg(valist,long));
                            break;
                    }
                    break;
            }
        }
    }
    va_end(valist);//清理为valist开辟的内存
}

int main()
{
    //创建变量
    int d = 12850;
    char c = 'g';
    double lf = 45854.8255;
    float f = 546.618;
    char str[] = "hello world !";
    long ld = 1564323;
    //调用自定义的my_print函数,测试是否能正确获取所有参数
    //参数的顺序和数量要严格对应
    my_printf("%d %f %c %ld %lf %s", d, f, c, ld, lf, str);
    return 0;
}

输出结果

int: 12850
float: 546.617981
char: g
long: 1564323
double: 45854.825500
char*: hello world !

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值