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");
    
  • 相关阅读:
    iOS----------上传遇到的问题
    iOS----------面试常问
    iOS----------Mac维修预约-如何找到电脑维修单
    iOS----------has copy command from(bug修复)
    关于powershell的个人总结
    关于powershell 的一些练习
    域控制总结
    Windows 常用命令
    注册表安全配置
    注册表危险操作
  • 原文地址:https://www.cnblogs.com/zhcpku/p/14128980.html
Copyright © 2011-2022 走看看