可变参...和 ##__VA_ARGS
基本使用方式如下,我主要用来记日志了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include <syslog.h> #include <stdarg.h> #include <stdio.h> #define BUFF_LEN_O 1024 #define LOGGER(priority, format, ...) do{ \ logger(priority, format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ }while(0) #define PRINT(x, a) printf("\n")
static void logger(int priority, const char *format, ...) { openlog("test_log", LOG_PID | LOG_NDELAY, LOG_LOCAL0); va_list ap; char buff[BUFF_LEN_O] = {0}; char placeholder[] = "function{%s},line{%d}"; va_start(ap, format); snprintf(buff, sizeof(buff) - 1, "%s %s", placeholder, format); vsyslog(priority, buff, ap); va_end(ap); }
int main() { LOGGER(LOG_INFO, "hello world %s", "123"); LOGGER(LOG_ERR, "new"); logger(LOG_INFO, "hello world %s", __FUNCTION__, __LINE__, "123"); return 0; }
|
#字符串化
会直接把表达式按照字符串输出,并过滤掉注释部分以及前后的空白。 1 2 3 4 5 6 7 8
| #include <stdio.h> #define PRINT(x) do {printf("\n"#x"\n");}while(0)
int main() { PRINT(print("hello world")); return 0; }
|
##Token拼接符号[^4]
这个就比较有意思了,可以通过这个结合gcc的typeof模拟出不少泛型的方式,在编译前预处理时扩展出不少函数或变量定义。参考[^4]文章的大佬用宏扩展出了弱图灵完备的函数。
按照大佬说的,这个库Cloak/cloak.h at master · pfultz2/Cloak非常多的例子
延迟展开
1 2 3 4 5 6 7 8 9
| #define EXPAND(...) __VA_ARGS__ #define EMPTY() #define DEFER(id) id EMPTY() #define FOO() printf("macro\n");
DEFER(FOO)()
EXPAND(DEFER(FOO)());
|
_Generic[^6]
使用方式,_Generic((var), type1 : ..., type2 : ..., ……, default : ...)
,感觉果然和大佬们说的一样,比较像是对基本类型进行switch。
比起这个,可能gcc内建的像typeof这些关键字用起来更具有扩展性。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include <stdio.h> #include <complex.h> #define CUSTOM_GENERIC(_var_) _Generic((_var_), \ signed char : printf("type signed char, var:%d\n", _var_), \ signed short : printf("type signed short, var:%hd\n", _var_), \ signed int : printf("type signed int, var:%d\n", _var_), \ signed long int : printf("type signed long int, var:%ld\n", _var_), \ signed long long int : printf("type signed long long int, var:%lld\n", _var_), \ unsigned char : printf("type unsigned char, var:%c\n", _var_), \ unsigned short : printf("type unsigned short, var:%hu\n", _var_), \ unsigned int : printf("type unsigned int, var:%u\n", _var_), \ unsigned long int : printf("type unsigned long int, var:%lu\n", _var_), \ unsigned long long int : printf("type unsigned long long int, var:%llu\n", _var_), \ float : printf("type float, var:%f\n", _var_), \ double : printf("type double, var:%lf\n", _var_), \ long double : printf("type long double, var:%llf\n", _var_), \ _Bool : printf("type _Bool, var:%d\n", _var_), \ float _Complex : printf("type float _Complex, var:%f+%fi\n", crealf(_var_), cimagf(_var_)), \ double _Complex : printf("type double _Complex, var:%f+%fi\n", creal(_var_), cimag(_var_)), \ long double _Complex : printf("type long double _Complex, var:%lf+%lfi\n", creall(_var_), cimagl(_var_)), \ default : printf("type default!") \ ) int main(void) { int a = 10; float f = 100.0f; float _Complex fCex = 100.0f + 1.0if; CUSTOM_GENERIC(a); CUSTOM_GENERIC(f); CUSTOM_GENERIC(fCex); CUSTOM_GENERIC(12); return 0; }
|
Reference
- 宏定义的黑魔法 - 宏菜鸟起飞手册
- C preprocessor - Wikipedia
- C11新增关键字:_Generic(泛型)_c/c++_南雨兮-CSDN博客
- 宏定义黑魔法-从入门到奇技淫巧 (3) | Feng.Zone
最后更新时间:
欢迎评论~