如何修改C语言可变参数宏print()以支持无参数传入不报错?
解决C语言
print宏处理空参数的问题 问题根源
调用print()无参数时,原宏中的int array[] = {__VA_ARGS__}会展开为int array[] = {},这不符合C标准(C不允许自动存储期的数组空初始化),直接触发编译错误;同时空__VA_ARGS__会导致宏展开语法异常。
修改方案
利用C11标准的_Generic特性与宏粘贴运算符##,区分有无参数的场景,避免空数组初始化问题:
修改后的完整代码
#include <stdio.h> #include <stdarg.h> void function_for_printing(int len, ...) { va_list args; va_start(args, len); if (len > 0) { for (int i = 0; i < len; i++) { int temp = va_arg(args, int); printf("%d ", temp); } printf("\n"); } else { printf("Nothing passed\n"); } va_end(args); printf("\n"); } // 辅助宏:处理有参数的情况 #define _PRINT_HAS_ARGS(...) \ do { \ int array[] = {__VA_ARGS__}; \ int size = sizeof(array)/sizeof(array[0]); \ function_for_printing(size, __VA_ARGS__); \ } while(0) // 辅助宏:处理空参数的情况 #define _PRINT_NO_ARGS() \ function_for_printing(0) // 核心宏:通过类型匹配区分有无参数 #define print(...) \ _Generic((int[]){0, ##__VA_ARGS__}, \ int[1]: _PRINT_NO_ARGS(), \ default: _PRINT_HAS_ARGS(__VA_ARGS__)) int main() { print(1, 2, 4); // 正常打印参数 print(1, 2, 3, 4, 5, 6, 7); // 正常打印参数 print(); // 正确输出"Nothing passed" return 0; }
代码说明
_Generic类型匹配:- 无参数时,
(int[]){0, ##__VA_ARGS__}展开为(int[]){0},类型为int[1],匹配_PRINT_NO_ARGS分支; - 有参数时,展开为
(int[]){0, arg1, arg2,...},类型为int[N](N>1),匹配_PRINT_HAS_ARGS分支。
- 无参数时,
##__VA_ARGS__的作用:当__VA_ARGS__为空时,##会删除前面的逗号,避免出现(int[]){0,}的语法错误。do-while(0)包裹宏:确保宏在任何上下文(如if语句后)都能正确展开,避免语法冲突。- 修复原函数的未定义行为:将
va_end(args)移至函数末尾统一调用,保证va_start与va_end成对出现。
简化方案(GCC专属)
若使用GCC编译器,可利用C23标准的__VA_OPT__扩展简化代码:
#define print(...) \ do { \ int array[] = {0 __VA_OPT__(,) __VA_ARGS__}; \ int size = sizeof(array)/sizeof(int) - 1; \ function_for_printing(size, __VA_OPT__(__VA_ARGS__, 0)); \ } while(0)
__VA_OPT__(,) __VA_ARGS__会在有参数时插入逗号分隔参数,无参数时为空;size通过数组总长度减1得到实际参数个数。
内容的提问来源于stack exchange,提问作者Sakib Khandaker
相关产品推荐
相关产品推荐

