【发布时间】:2022-11-05 16:18:28
【问题描述】:
所以,我想创建一个函数(类似宏),它接受任意数量的不同类型的参数并对它做一些事情。 我的意思是,我确实设法让它工作,但我正在寻找一个更优雅的解决方案(或确保我的方式是它应该看起来的方式)。
函数宏 print(...) 的示例代码:
#ifndef EVIL_PRINT_H
#define EVIL_PRINT_H
#include <stdio.h>
#define TWENTY_SECOND_ARGUMENT(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, ...) _22
#define COUNT_ARGUMENTS(...) TWENTY_SECOND_ARGUMENT(__VA_ARGS__, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define PRINT_CHAR_EVIL(x) printf("%c", x)
#define PRINT_INT_EVIL(x) printf("%i", x)
#define PRINT_FLOAT_EVIL(x) printf("%f", x)
#define PRINT_DOUBLE_EVIL(x) printf("%d", x)
#define PRINT_PTR_EVIL(x) printf("%p", x)
#define PRINT_STR_EVIL(x) printf("%s", x)
#define PRINT_ONE_EVIL(x, ...) _Generic(x, \
char: PRINT_CHAR_EVIL(x), \
int: PRINT_INT_EVIL(x), \
float: PRINT_FLOAT_EVIL(x), \
double: PRINT_DOUBLE_EVIL(x), \
void *: PRINT_PTR_EVIL(x), \
char const *: PRINT_STR_EVIL(x), \
char *: PRINT_STR_EVIL(x) \
)
#define PRINT_TWO_EVIL(_1, _2, ...) PRINT_ONE_EVIL(_1); PRINT_ONE_EVIL(_2)
...
#define PRINT_TWENTY_ONE_EVIL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, ...) PRINT_TWENTY_EVIL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20); PRINT_ONE_EVIL(_21)
#define print(...) do { \
switch (COUNT_ARGUMENTS(__VA_ARGS__)) { \
default:break; \
case 1: \
PRINT_ONE_EVIL(__VA_ARGS__); \
break; case 2: \
PRINT_TWO_EVIL(__VA_ARGS__, 2); \
... \
break; case 21: \
PRINT_TWENTY_ONE_EVIL(__VA_ARGS__, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21); \
} \
} while(0);
#endif
我对这种方法的问题是它为一个调用复制了很多代码,但我不知道,也许编译器优化了所有不需要的分支。还有一个限制是它不会接受超过 x(在我的情况下 - 21)数量的参数。添加更多参数没什么大不了的,但是如果您需要 100 多个参数,文件大小将会增加。
使用示例:
#include "evil_print.h"
int main(void) {
struct {
int i;
char c;
} v = {.i = 100, .c = 'A'}, o;
o = v;
print(v.i, ", ", o.c);
}
是的,我知道在 c++ 中很容易,这里不要提及该语言。
【问题讨论】:
-
C++ 需要为可变参数宏添加特殊语法是有原因的——使用 C 宏并不容易。
-
对于实际编译的代码,使用预处理器输出查看。 ——无论如何,你的用例是什么? 40 多年的 C 编程,显然数以百万计的程序员认为没有迫切需要这种结构。好的,我可以用锤子在墙上拧螺丝,但它是高质量工作的正确工具吗?
-
我确实检查了预处理器的输出,这是我所期望的(我真的希望编译器在编译可执行文件时优化分支)。是的,当然,其他人不需要它,但拥有它很方便。
标签: c generics macros variadic-macros