如何捕获传入无参函数void fun1()的实参值?需保留现有代码格式
解决方案:保留原代码格式并捕获fun1的实参
这问题挺有意思的——既要保留原代码的格式不动,又要捕获fun1调用时的实参值,幸好C的预处理器和旧式函数声明特性能帮我们搞定这件事。
核心思路
原代码中void fun1()是旧式C函数声明,它表示函数接受任意数量/类型的参数(和void fun1(void)明确无参的声明不同),所以fun1(5)的调用是合法的。我们可以利用预处理器宏来包装fun1,在不修改原函数代码和调用代码的前提下,插入参数捕获逻辑。
完整实现代码
#include <stdio.h> #include <stdarg.h> // 第一步:临时重命名原fun1,避免和后续宏冲突 #define fun1 _real_fun1 void fun1() { puts("In fun1\n"); } #undef fun1 // 第二步:定义宏fun1,实现参数捕获+调用原函数 #define fun1(...) do { \ /* 捕获并打印参数 */ \ printf("Captured fun1 argument: "); \ /* 利用GNU扩展##__VA_ARGS__处理无参情况 */ \ if(sizeof((int[]){0, ##__VA_ARGS__}) > sizeof(int)) { \ va_list args; \ va_start(args, NULL); \ int arg = va_arg(args, int); \ printf("%d\n", arg); \ va_end(args); \ } else { \ printf("(no argument)\n"); \ } \ /* 调用原函数 */ \ _real_fun1(__VA_ARGS__); \ } while(0) // 以下是原代码,完全未修改 void fun2(void) { puts("In fun2\n"); } main() { fun1(); fun1(5); fun2(); }
代码解释
- 重命名原函数:通过
#define fun1 _real_fun1把原fun1的定义替换成_real_fun1,这样后续定义的宏fun1不会和原函数冲突,同时原函数的代码完全保留。 - 宏包装逻辑:
- 用
do{...}while(0)确保宏在任何场景下都能安全执行(比如放在if语句里不会出语法问题)。 sizeof((int[]){0, ##__VA_ARGS__})用来判断是否有参数:如果无参,数组只有一个元素0,大小是sizeof(int);如果有参,数组会包含0和传入的参数,大小大于sizeof(int)。- 用
va_list获取并打印实参值,然后调用原函数_real_fun1。
- 用
注意事项
- 上述代码用到了GNU C的
##__VA_ARGS__扩展,用来处理无参时的宏展开问题。如果需要兼容标准C(C11及以前),可以改用条件判断宏或者针对无参/有参分别处理:// 标准C兼容的宏写法(仅针对无参和单个int参数的情况) #define fun1(...) _Generic((int[]){0, ##__VA_ARGS__}, \ int[1]: _fun1_no_arg(), \ int[2]: _fun1_with_arg(__VA_ARGS__)) void _fun1_no_arg() { printf("Captured fun1 argument: (no argument)\n"); _real_fun1(); } void _fun1_with_arg(int arg) { printf("Captured fun1 argument: %d\n", arg); _real_fun1(arg); } - 原代码的
main()写法是旧式C风格,建议改成int main(void)以符合现代C标准,但按照你的要求我们保留了原格式。
内容的提问来源于stack exchange,提问作者Huzaifah
相关产品推荐
相关产品推荐

