欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

可变参数列表解析及模拟实现printf函数

程序员文章站 2022-03-08 15:01:03
...

可变参数列表解析及模拟实现printf函数

我们学过很多函数,他们都有参数,而且参数的个数都是固定的。但是用的时候我们设计函数函数时却血药参数不是固定为好。例如:我们设计一个求平均数的函数,当求两个平均数时我们会传2个参数,三个数的平均数传3个参数………如果要在一个函数中实现n个数的平均值,这里我们就得靠可变参数列表来实现。
下来先看一个简单的例子,使用可变参数,实现函数求未知参数部分n个数的平均值
代码如下:

#include <stdio.h>
#include<stdarg.h>
int average(int n, ...)
{
    va_list arg;
    int i = 0;
    int sum = 0;
    va_start(arg, n);
    for (i = 0; i < n; i++)
    {
        sum += va_arg(arg, int);
    }
    return sum / n;
    va_end(arg);
}
int main()
{
    printf("%d\n", average(3, 5, 6, 7));
    printf("%d\n", average(6, 1, 2, 3, 4,5,9));
    return 0;
}

运行结果:
可变参数列表解析及模拟实现printf函数
1.va_list定义了一个arg变量,它用于访问参数列表未确定的部分。
2.va_start对其进行初始化,其第一个参数是va_list变量的名字,第二个参数是省略号前第一个有名字的参数。在初始化的过程,arg被设置为指向可变参数部分第一个参数。
3.为了访问访问参数,我们需要使用va_arg。va_arg这个宏接受两个参数,va_list定义的参数和列表中下一个参数的类型。va_arg返回这个参数的值,并且指向下一个可变参数。
4.最后,访问完最后一个参数时,需要调用va_end将指针置为无效。

va_start宏的定义如下

#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )**
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

_INTSIZEOF(n)作用:将n的长度化为int长度的整数倍。

va_arg宏定义如下

#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

va_arg作用:返回参数的值,并使arg指向下一个参数。

va_end定义如下

#define va_end(ap) ( ap = (va_list)0 )

va_end作用:指针置为无效。

注意:

  • 可变参数列表必须按照顺序从头到尾逐个访问,当你在访问几个可变参数后想半途中止,这是可以的。但是如果你一开始就想访问中间的参数,那是不行的。
  • 参数列表中至少要有一个命名参数。如果连一个命名参数都没有,就无法使用va_start。
  • 这些宏无法直接判断实际存在参数的数量。
  • 这些宏无法判断每个参数的类型。
  • 如果va_arg中指定了错误的类型,那么后果是不可预测的。

    printf函数的实现
    代码如下

#include "stdio.h"
#include "stdarg.h"
void show(int n)
{
    if (n > 9)
    {
        show(n / 10);
    }
    putchar(n % 10 + '0');
}
void print(const char *format, ...)
{
    va_list arg;
    va_start(arg, format);
    while (*format)
    {
        switch (*format)
        {
        case 's':
        {
            char* ret = va_arg(arg, char*);
            while (*ret)
            {
                putchar(*ret);
                ret++;
            }
            break;
        }
        case 'c':
        {
            int ch = va_arg(arg, char);
            putchar(ch);
        }
        break;
        case 'd':
        {
            int ret = va_arg(arg, int);
            show(ret);
        }
        break;
        default:
            putchar(*format);
            break;
        }
        format++;
    }
}

int main()
{
    print("s ccc d.\n", "hello", 'b', 'i', 't', 100);
    return 0;
}

运行结果:

可变参数列表解析及模拟实现printf函数

相关标签: printf