• C库中对函数的可变参数的支持


    C语言在<stdarg.h> 头文件定义了一些宏,当函数参数未知时去获取函数的参数。
    包括一个va_list类型和三个函数(宏)va_start, va_arg和va_end .
    变量和定义
    va_list类型通过stdarg宏定义来访问一个函数的参数表,参数列表的末尾会用省略号省略

    声明:void va_start(va_list ap, last_arg);
    用va_arg和va_end宏初始化参数ap,last_arg是传给函数的固定参数的最后一个,省略号之前的那个参数注意va_start必须在使用va_arg和va_end之前调用

    声明:type va_arg(va_list ap, type);

    用type类型扩展到参数表的下个参数
    注意ap必须用va_start初始化,如果没有下一个参数,结果会是undefined

    声明:void va_end(va_list ap); 允许一个有参数表(使用va_start宏)的函数返回,如果返回之前没有调用va_end,结果会是undefined。参数变量列表可能不再使用(在没调用va_start的情况下调用va_end)

    windows下的定义如下:
     #ifndef _VA_LIST_DEFINED  
        #ifdef  _M_ALPHA  
        typedef struct {  
                char *a0;       /* pointer to first homed integer argument */  
                int offset;     /* byte offset of next parameter */  
        } va_list;  
        #else  
        typedef char *  va_list;  
        #endif  
        #define _VA_LIST_DEFINED  
        #endif  
          
        #ifdef  _M_IX86       
          
        #define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )  
        #define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )  
        #define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )  
        #define va_end(ap)      ( ap = (va_list)0 )  
          
        #elif   defined(_M_MRX000) 
      
    其中比较不容易理解的就是_INTSIZEOF宏:其实_INTSIZEOF(n)表示得到变量n的内存大小,这里要考虑内存对齐问题,在32位中系统中,一般是4字节(32位)对齐。(sizeof(n) + sizeof(int))表示凑成4字节的整数被,(sizeof(n) + sizeof(int)) & (sizeof(int) -1)表示将凑齐后多余的字节删除。比如说10字节的变量,占内存的大小为:(10+4)&((11111100)2)= 12字节;

    C语言中利用可变参数的函数就是最常用的printf。而且C标准库中也是包括3个参数含有va_list的函数:vprintf,vfprintf,vsprintf。而这三个函数与对应的不加“v“的函数用法是一样的,只不过,vprintf类要求可变参数用va_list指定。其实printf就是利用vprintf来实现的。

    下面是一个模仿printf的函数:
    #include <stdio.h>
     #include <stdarg.h>
     void print(char* fmt,...){
         va_list ap;
         int d;
         char c,*s;
         double f;
         va_start(ap, fmt);
         while(*fmt)
             switch(*fmt++){
                 case 's':
                     s=va_arg(ap,char*);
                     printf("string: %s\n",s);
                     break;
                 case 'd':
                     d=va_arg(ap,int);
                     printf("int: %d\n",d);
                     break;
                 case 'c':
                     c=(char)va_arg(ap,int);
                     printf("char: %c\n",c);
                     break;
                 case 'f':
                     f=va_arg(ap,double);
                     printf("double: %f\n",f);
                     break;
             }
         va_end(ap);
     }
     int main(){
         char* s="hello world";
         char c='H';
         int d=333;
         double f=79.998;
         print("%s %d %c %f",s,d,c,f);
     }
  • 相关阅读:
    Python之CVXOPT模块
    JavaScript之读取和写入cookie
    jQuery学习(2)ajax()使用
    JavaScript之使用AJAX(适合初学者)
    Jquery焦点图实例
    jquery-mobile表单提交问题
    程序员笔记|Spring IoC、面向切面编程、事务管理等Spring基本概念详解
    使用什么调试swoole程序
    swoole模块的编译安装:php编译安装swoole模块的代码
    TP5使用Redis处理电商秒杀
  • 原文地址:https://www.cnblogs.com/xkfz007/p/2720625.html
Copyright © 2020-2023  润新知