C语言变参的实现

今天本来想定位下项目中日志打印部分的错误,尝试在变参的个数匹配不上时,编译给出warning或error,可惜弄了半天也没实现。

个人测试实现的变参函数代码如下,虽是测试代码,但也基本写明了变参的实现过程,需要注意的问题和相关要点都写在注释中了,下面上代码。

如果有哪位大侠能够给出我上面提到的warning和error的生成建议,欢迎留言或给我私信交流。废话少说,上代码了,可以直接g++ variable_arg.cpp编译成功。

/* 
 * File:   variable_arg.cpp
 * Author: Carl
 *
 * Created on August 28, 2012, 5:25 PM
 */

#include <cstdlib>
#include <cstdio>
#include <stdarg.h>
#include <cstring>

using namespace std;

/*
 * 1)C标准规定实现可变参数机制的函数至少要有一个固定参数。
 * 2)隐式类型不可用。例如,va_arg指定了类型是double,若传入的是int类型的变量10,就会报错
 * 3)C语言的整型提升原则。也就是说,在va_arg中获取float和double使用的type是double,而获取char,short和int使用的type是int
 * 4)函数指针不可用,除非用typedef定义过
 */

void miniprintf(const char *fmt, ...)
{
    va_list ap; //声明一个对象,用来盛放参数,一个char链表(实际应该是一个连续的内存块,像数组一样),表现为一个指向char类型的指针
    int d;
    char c, *p, *s;
    double f;

    //初始化va_list,通过最后的固定参数实现对可变参数初始位置的定位,并未va_list分配内存,将可变参数复制到该内存块中,是va_list指向给内存块的初始位置
    va_start(ap, fmt); //ap指向第一个(不是第0个)参数,fmt后面的那个
    while (*fmt)
    {
        if (*fmt != '%') //普通字符直接输出
        {
            putchar(*fmt++);
            continue;
        }
        fmt++; //格式化字符,++指向s,d之类的格式字符位
        switch (*fmt++) //此处的++,目的是指向格式字符位的下一位,为下次loop准备
        {
            //根据相应格式来取到对应的匹配参数
        case 's':
            //va_arg,通过移动指针va_list获取由参数type(第二个参数)指定的变量,并返回该变量
            s = va_arg(ap, char *);
            printf("%s", s);
            break;
        case 'd':
            d = va_arg(ap, int);
            printf("%d", d);
            break;
        case 'c':
            c = (char) va_arg(ap, int);
            printf("%c", c);
            break;
        case 'f':
            f = va_arg(ap, double);
            printf("%f", f);
            break;
        default: //不被支持的格式字符
            printf("the format [%c] is not supported", *fmt);
            break;
        }
    }
    va_end(ap); //这个最好都要调用一次,在有的C实现中,可能用来释放va_start为va_list分配的内存
    return;
}

double sum(int lim, ...)
{
    va_list ap;
    double total = 0;
    int i;
    va_start(ap, lim);
    for (i = 0; i < lim; i++)
    {
        total += va_arg(ap, double); //依次取到每个参数
    }

    va_end(ap);
    return total;
}

int main(int argc, char** argv)
{
    char str[10];
    memset(str, 0, sizeof (str));
    memcpy(str, "hello", 5);
    miniprintf("this is the string \"%s\", \nthis is the int %d, \nthis is the character %c\n", str, 3, 'a');

    double total = 0;
    total = sum(5, 10.0, 20.0, 30.0, 40.0, 50.0);       //这里如果是10,20这种int型的数据,会得到错误的结果
    miniprintf("total is %f\n", total);
    return 0;
}

运行结果如下

this is the string "hello", 
this is the int 3, 
this is the character a
total is 150.000000

水平有限,如果有朋友发现错误,欢迎留言交流。
转载请保留本文链接,如果觉得我的文章能帮到您,请顶一下。,谢谢。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值