zoukankan      html  css  js  c++  java
  • [C语言]变长函数参数和变长参数宏

    C++里对于变化长参数已经有了较好的处理方案,这里对C语言的变长参数进行一个简答的总结。主要分为两块:函数和宏。

    函数的变长参数

    常见于printf系列函数,以printf的实现为例:

    int printf (const char *format, ...) {
      va_list arg;
      int done;
    
      va_start (arg, format);
      done = vfprintf (stdout, format, arg);
      va_end (arg);
    
      return done;
    }
    

    主要用到了va_list系列宏,定义在stdarg.h头文件中。
    注意,va_start是把操作指针移动到了变长参数头部,如果需要对变长参数操作多次,需要首先使用va_copy(dst,src)对变长参数进行备份。

    宏的变长参数

    宏的变长参数可用于定义一个自定义附加信息的assert:

    #define vassert(expr, fmt, ...)                               
        do {                                                      
            if (!(expr)) {                                        
                char *msg;                                        
                asprintf(&msg, fmt, ##__VA_ARGS__);               
                __assert_fail(msg, __FILE__, __LINE__, __func__); 
            }                                                     
        } while (0)
    

    这里用到的是__VA_ARGS__宏,C99中被标准化,编译时自动替换为实际对应的参数集。
    ##的作用是正确处理变长参数为空的情况。

    题外话:

    这里我们可以额外加入一个宏,使得vassert具有和assert一样的开关性质。

    #ifdef NDEBUG
          #define vassert(expr, fmt, ...) ((void)0)
    #else
          #define vassert(expr, fmt, ...) 
                ...
    #endif
    

    使用 #define vassert(expr, fmt, ...) ((void)0) 而非简单的 #define vassert(expr, fmt, ...) 或者 #define vassert(expr, fmt, ...) {},是因为这种写法能正常用于逗号表达式,或者条件语句,且能被编译器自动识别进行空语句优化。

    // Comma expression
    printf("test"), vassert(0, "fail");
    
    // Conditional expression
    test-expr ? perror("Hello") : vassert(0, "fail");
    
  • 相关阅读:
    DOM笔记(二):Node接口
    DOM笔记(一):HTMLDocument接口
    mysql_connect v/s mysql_pconnect
    HTML 5:绘制旋转的太极图
    HTML 5:你必须知道的data属性
    CSS:7个你可能不认识的单位
    CSS 3的display:盒类型详解
    PHP:6种GET和POST请求发送方法
    asp.net mvc生命周期学习
    关于sql row_number,rank,dense_rank,ntile函数
  • 原文地址:https://www.cnblogs.com/zhcpku/p/14128980.html
Copyright © 2011-2022 走看看