C语言可变参数实现

概述

C语言编程中会遇到一些参数个数可变的函数,例如printf()这个函数,它的定义是这样的

  int printf( const char* format, ...);


  它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的,例如我们可以有以下不同的调用方法

printf("%d",i); 
  printf("%s",s); 
  printf("the number is %d ,string is:%s", i, s);


   究竟如何写可变参数的C函数以及这些可变参数的函数编译器是如何实现的呢?本文就这个问题进行一些探讨.

实现原理

2.1 printf实现原理

该实现使用了va_start、va_arg、va_end。如下,

l va_list

   va_list表示可变参数列表类型,实际上就是一个char指针.

l va_start

   va_start用于获取函数可变参数列表(获取函数参数列表中可变参数的首指针 

输出参数ap(类型为va_list): 用于保存函数参数列表中可变参数的首指针

输入参数A: 为函数参数列表中最后一个固定参数

l va_arg

   va_arg用于获取当前ap所指的可变参数并将并将ap指针移向下一可变参数
    * 输入参数ap(类型为va_list): 可变参数列表,指向当前正要处理的可变参数
    * 输入参数T: 正要处理的可变参数的类型
    * 返回值当前可变参数的值

l va_end

   va_end用于结束对可变参数的处理。实际上,va_end被定义为空.它只是为实现与va_start配对(实现代码对称和"代码自注释"功能)

 

2.2 printf实现代码

void print(const char *fmt, ...)
{
    char str[100];
    unsigned int len, i, index;
    int iTemp;
    char *strTemp;
    va_list args;

    va_start(args, fmt);
    len = strlen(fmt);
    for (i=0, index=0; i<len; i++)
    {
        if (fmt[i] != '%')    /* 非格式化参数 */
        {
            str[index++] = fmt[i];
        }
        else                /* 格式化参数 */
        {
            switch(fmt[i+1])
            {
            case 'd':        /* 整型 */
            case 'D':
                iTemp = va_arg(args, int);
                strTemp = itoa(iTemp, str+index);
                index += strlen(strTemp);
                i++;
                break;
            case 's':        /* 字符串 */
            case 'S':
                strTemp = va_arg(args, char*);
                strcpy(str + index, strTemp);
                index += strlen(strTemp);
                i++;
                break;
            default:
                str[index++] = fmt[i];
            }
        }
    }
    str[index] = '\0';
    va_end(args);       
}

3 Linux内核实现

/*
  * Use local definitions of C library macros and functions
  * NOTE: The function implementations may not be as efficient
  * as an inline or assembly code implementation provided by a
  * native C library.
  */

#ifndef va_arg

#ifndef _VALIST
#define _VALIST
typedef char *va_list;
#endif                /* _VALIST *//*
 * Storage alignment properties
 */
#define _AUPBND (sizeof (acpi_native_int) - 1)
#define _ADNBND (sizeof (acpi_native_int) - 1)/*
 * Variable argument list macro definitions
 */
#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))
#define va_arg(ap, T) (*(*)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
#define va_end(ap) (void) 0
#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))

#endif                /* va_arg */

 

4 _vsnprintf

函数声明:

int _vsnprintf(char* str, size_t size, const char* format, va_list ap);

参数说明:

char *str [out],把生成的格式化的字符串存放在这里.

size_t size [in], str可接受的最大字节数,防止产生数组越界.

const char *format [in], 指定输出格式的字符串,它决定了你需要提供的可变参数的类型、个数和顺序。

va_list ap [in], va_list变量. va:variable-argument:可变参数

函数功能:将可变参数格式化输出到一个字符数组。

用法类似于vsprintf,不过加了size的限制,防止了内存溢出(sizestr所指的存储空间的大小)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值