c语言语法——c语言函数不定参数实现方式

c语言不定参数

va函数的定义和宏

va函数定义

typedef char* va_list;//x86平台下va_list的定义
type va_arg(va_list argptr, type);  
void va_end(va_list argptr);  
void va_start(va_list argptr, last_parm);  

va_list
定义一个指针arg_ptr,用于指示可选的参数。
va_start(arg_ptr, argN)
使参数列表指针arg_ptr指向函数列表中的第一个可选参数,argN是位于第一个可选参数之前的固定参数(最后一个固定参数)。
va_arg(arg_ptr, type)
返回参数列表中指针arg_ptr所指的参数,返回类型为type。并使指针arg_ptr指向参数列表中下一个参数。返回的是可选参数,不包括固定参数。
va_end(arg_ptr)
清空参数列表

va宏

va的宏定义在stdarg.h中,有:va_list,va_start(),va_arg(),va_end()。

#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1)) //类型n的大小,这是考虑了字节对齐
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //ap指向第一个不定参数地址
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址  返回当前ap指向的值,并且增加ap
#define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效

读取可变参数的过程其实就是堆栈中,使用指针遍历堆栈段中的参数列表,从低地址到高地址一个一个地把参数内容读出来的过程。

1. 所有类型的固定参数都必须出现在参数列表的开始。
2. 在设计具有不定参数列表的函数的时候,我们有两种方法来确定到底有多少参数会被传递进来:

  • 在类型固定的参数中指明后面有多少个参数以及他们的类型。printf就是采用这种方法,它的format参数指明后面每个参数的类型。
  • 指定一个结束参数。这种情况一般是不定参数拥有同样的类型,我们可以指定一个特定的值来表示参数列表结束。

va函数自定义printf

通过va函数和系统函数write简单实现了打印整型,浮点型,字符和字符串的功能。

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>

int print(char* format, ...){
    va_list args;
    va_start(args, format);
    char* formatChild = format;
    char* tmp = formatChild;
    //char* buff;
    while(1){
        if(*formatChild == 0){
            break;
        } 
        if(!strstr(formatChild, "%")){
            write(2, formatChild, strlen(formatChild));
            break;
        }
        tmp = formatChild;
        formatChild = strstr(formatChild, "%");
        write(2, tmp, formatChild-tmp);

        switch(*(formatChild+1)){
            case 'd':{
                int itmp = va_arg(args, int);
                char buff[32];
                sprintf(buff, "%d", itmp);
                write(2, buff, strlen(buff));
                formatChild += 2;
                break;
            }
            case 'f':{
                float ftmp = (float)va_arg(args, double);
                char buff[32];
                sprintf(buff, "%f", ftmp);
                write(2, buff, strlen(buff));
                formatChild = formatChild+2;
                break;
            }
            case 'c':{
                char ctmp = va_arg(args, int);
                write(2, &ctmp, sizeof(char));
                formatChild = formatChild+2;
                break;
            }
            case 's':{
                char* strTmp = va_arg(args, char*);
                write(2, strTmp, strlen(strTmp));
                formatChild = formatChild+2;
                break;
            }       
        }
    }
    va_end(args);
}

int main(int argc, char* arg[]){
    print("%d %f %c %s", 1, 1.0, '1', "11111111");
}

运行结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值