最直观的--函数可变参数数量的实现讲解(二)va_start、va_arg、va_end的使用

文章探讨了C语言中实现可变参数函数的方法,以printf_test为例,详细解释了如何利用stdarg.h头文件中的va_start、va_arg和va_end宏来处理可变参数列表。通过vprintf函数的引入,进一步优化了printf_test,使其能处理任意数量的参数。
摘要由CSDN通过智能技术生成

在“最直观的--函数可变参数数量的实现讲解(一)”中,我们站在上帝视角,实现了int printf_test (const char *__format, ...),现在我们接着玩。。。

打开printf_test和printf两个函数,他们的对应关系,大概是这个样子:

那么,运行程序的机器没有上帝的视角,怎么知道我们传递的参数个数和类型呢?

其实,这也是我们设计好的:

int printf (const char *__format, ...)中,第一个参数__format是固定的,要使用字符串指针(const char *),机器通过我们这个字符串指针指向的字符串内容,一步步解析,推测我们后面传递的参数。

例如printf      ("%s, %2d, Hello, World, %d!", __func__, __LINE__, data);

1.我们传递的字串内容是"%s, %2d, Hello, World, %d!";

2.机器先检查到%s,就知道,我们第二个参数,要传递字符串,我这里传了函数名进去;

3.然后机器继续解析,遇到%2d,机器就知道,我们第三个参数要传整形,我这里传来行号进去;

4.机器再解析,遇到%d,同样知道我们最后一个参数也是整形,我这里传data的值进去了;

5.字符串"%s, %2d, Hello, World, %d!"解析完毕,printf的工作也就基本完成了。

这个实现过程蛮复杂的,我就不操作了。。。。

接下来,我们看头文件<stdarg.h>的3个宏va_startva_argva_end

va_startva_argva_end三个宏在项目中比较实用的。现在,我们用他们实现printf_test功能:

#include <stdio.h>

#include <stdarg.h>

static int printf_test (const char *__format, ...)

{

    va_list p_args;                                     // 声明va_list(const char *)变量

    va_start(p_args, __format);                         // __format一定是...前的第一个参数

    const char * func = va_arg(p_args, const char *);   // 得到__func__

    int line = va_arg(p_args, int);                     // 得到__LINE__

    int data = va_arg(p_args, int);                     // 得到data

    va_end(p_args);                                     // 结束

    printf("\n%s, %d\n", __func__, __LINE__);

    printf("%s, %s, %d, %d", __format, func, line, data);

    printf("\n\n");

    return 0;

}

int main (void * arg)

{

    int data = 1;

    printf      ("%s, %2d, Hello, World, %d!", __func__, __LINE__, data);

    printf      ("\n");

    printf_test ("%s, %2d, Hello, World, %d!", __func__, __LINE__, data);

    printf      ("\n");

    return 0;

}

运行结果:

main, 23, Hello, World, 1!

printf_test, 13

%s, %2d, Hello, World, %d!, main, 25, 1

接下来,我们对printf_test函数继续改进,先介绍一下vprintf函数

原型:int vprintf (const char *__format, __builtin_va_list __local_argv)

它是printf的双胞胎函数,里面用__builtin_va_list替换了…

#include <stdio.h>

#include <stdarg.h>

static int printf_test (const char *__format, ...)

{

    va_list p_args;                                     // 声明va_list(const char *)变量

    va_start(p_args, __format);                         // __format一定是...前的第一个参数

    printf("\n");

    vprintf(__format, p_args);

    va_end(p_args);

    printf("\n");

    return 0;

}

int main (void * arg)

{

    int data = 1;

    printf      ("%s, %2d, Hello, World, %d!", __func__, __LINE__, data);

    printf      ("\n");

    printf_test ("%s, %2d, Hello, World, %d!", __func__, __LINE__, data);

    printf      ("\n");

    return 0;

}

运行结果

main, 19, Hello, World, 1!

main, 21, Hello, World, 1!

这样,printf_test就实现了真正意义上的可变参数数量;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

钓鱼lalala

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值