用于 C 的 Varargs `ELEM` 宏
Posted
技术标签:
【中文标题】用于 C 的 Varargs `ELEM` 宏【英文标题】:Varargs `ELEM` macro for use with C 【发布时间】:2014-07-19 04:37:45 【问题描述】:我想知道是否有一个通用的ELEM
比较宏,其中:
(v == a || v == b)
可以替换为:
ELEM(v, a, b)
当然这可以通过宏来完成,
#define ELEM(v, a, b) (((v) == (a)) || ((v) == (b)))
但是,您最终需要使用参数计数定义多个宏。
使用一个简单的 python 脚本我想出了这个:
#define ELEM2(v, a, b) \
(((v) == (a)) || ((v) == (b)))
#define ELEM3(v, a, b, c) \
(ELEM2(v, a, b) || ((v) == (c)))
#define ELEM4(v, a, b, c, d) \
(ELEM3(v, a, b, c) || ((v) == (d)))
#define ELEM5(v, a, b, c, d, e) \
(ELEM4(v, a, b, c, d) || ((v) == (e)))
#define ELEM6(v, a, b, c, d, e, f) \
(ELEM5(v, a, b, c, d, e) || ((v) == (f)))
#define ELEM7(v, a, b, c, d, e, f, g) \
(ELEM6(v, a, b, c, d, e, f) || ((v) == (g)))
#define ELEM8(v, a, b, c, d, e, f, g, h) \
(ELEM7(v, a, b, c, d, e, f, g) || ((v) == (h)))
#define ELEM9(v, a, b, c, d, e, f, g, h, i) \
(ELEM8(v, a, b, c, d, e, f, g, h) || ((v) == (i)))
#define ELEM10(v, a, b, c, d, e, f, g, h, i, j) \
(ELEM9(v, a, b, c, d, e, f, g, h, i) || ((v) == (j)))
#define ELEM11(v, a, b, c, d, e, f, g, h, i, j, k) \
(ELEM10(v, a, b, c, d, e, f, g, h, i, j) || ((v) == (k)))
#define ELEM12(v, a, b, c, d, e, f, g, h, i, j, k, l) \
(ELEM11(v, a, b, c, d, e, f, g, h, i, j, k) || ((v) == (l)))
#define ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l, m) \
(ELEM12(v, a, b, c, d, e, f, g, h, i, j, k, l) || ((v) == (m)))
#define ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) \
(ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l, m) || ((v) == (n)))
#define ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) \
(ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) || ((v) == (o)))
#define ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
(ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) || ((v) == (p)))
来自这个 python3 脚本:
ELEM_TOTAL = 16
for i in range(2, ELEM_TOTAL + 1):
print("#define ELEM%d(" % i, end="")
print("v, ", end="")
args = [chr(ord('a') + j) for j in range(i)]
print(", ".join(args), end="")
print(") \\\n (", end="")
if i == 2:
print("((v) == (a)) || ((v) == (b))", end="")
else:
print("ELEM%d(v, %s) || ((v) == (%s))" % (i - 1, ", ".join(args[:-1]), args[-1]), end="")
print(")")
但我想知道是否有任何常用的 ELEM
宏可以接受可变数量的参数,并且至少可移植到足以与流行的 C 编译器(GCC、Clang、Intel、MCVC)一起使用。
【问题讨论】:
【参考方案1】:根据this question 的答案,我有一个可变参数 ELEM 宏,我认为它可以很好地移植,虽然它依赖于__VA_ARGS__
,但我认为这无济于事。
使用示例:
if (ELEM(var, A, B))
....
else if (ELEM(var, C, D, E, F, G))
....
实施:
#include <stdio.h>
/* ------ */
/* Macros */
/* internal helpers */
#define _VA_NARGS_GLUE(x, y) x y
#define _VA_NARGS_RETURN_COUNT(_1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, count, ...) count
#define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args
#define _VA_NARGS_COUNT_MAX16(...) _VA_NARGS_EXPAND((__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
#define _VA_NARGS_OVERLOAD_MACRO2(name, count) name##count
#define _VA_NARGS_OVERLOAD_MACRO1(name, count) _VA_NARGS_OVERLOAD_MACRO2(name, count)
#define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count)
/* expose for re-use */
#define VA_NARGS_CALL_OVERLOAD(name, ...) _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, _VA_NARGS_COUNT_MAX16(__VA_ARGS__)), (__VA_ARGS__))
/* ---------- */
/* ELEM Macro */
/* internal helpers*/
#define _VA_ELEM3(v, a, b) \
(((v) == (a)) || ((v) == (b)))
#define _VA_ELEM4(v, a, b, c) \
(_VA_ELEM3(v, a, b) || ((v) == (c)))
#define _VA_ELEM5(v, a, b, c, d) \
(_VA_ELEM4(v, a, b, c) || ((v) == (d)))
#define _VA_ELEM6(v, a, b, c, d, e) \
(_VA_ELEM5(v, a, b, c, d) || ((v) == (e)))
#define _VA_ELEM7(v, a, b, c, d, e, f) \
(_VA_ELEM6(v, a, b, c, d, e) || ((v) == (f)))
#define _VA_ELEM8(v, a, b, c, d, e, f, g) \
(_VA_ELEM7(v, a, b, c, d, e, f) || ((v) == (g)))
#define _VA_ELEM9(v, a, b, c, d, e, f, g, h) \
(_VA_ELEM8(v, a, b, c, d, e, f, g) || ((v) == (h)))
#define _VA_ELEM10(v, a, b, c, d, e, f, g, h, i) \
(_VA_ELEM9(v, a, b, c, d, e, f, g, h) || ((v) == (i)))
#define _VA_ELEM11(v, a, b, c, d, e, f, g, h, i, j) \
(_VA_ELEM10(v, a, b, c, d, e, f, g, h, i) || ((v) == (j)))
#define _VA_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) \
(_VA_ELEM11(v, a, b, c, d, e, f, g, h, i, j) || ((v) == (k)))
#define _VA_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) \
(_VA_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) || ((v) == (l)))
#define _VA_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) \
(_VA_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) || ((v) == (m)))
#define _VA_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) \
(_VA_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) || ((v) == (n)))
#define _VA_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) \
(_VA_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) || ((v) == (o)))
#define _VA_ELEM17(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
(_VA_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) || ((v) == (p)))
/* reusable ELEM macro */
#define ELEM(...) VA_NARGS_CALL_OVERLOAD(_VA_ELEM, __VA_ARGS__)
/* ------- */
/* Example */
int main(void)
int i;
i = 1 + 1;
printf("Test 1+1, in (3, 2, 1)? -> %d\n", ELEM(i, 3, 2, 1));
i = 22;
printf("Test 22, in (2/4, 10*2, 42, 100, 44/3)? -> %d\n", ELEM(i, 2 / 4, 10 * 2, 42, 100, 44 / 3));
return 0;
注意,_VA_ELEM#
使用此 python3 脚本生成:
ELEM_TOTAL = 16
for i in range(2, ELEM_TOTAL + 1):
print("#define _VA_ELEM%d(" % (i + 1), end="")
print("v, ", end="")
args = [chr(ord('a') + j) for j in range(i)]
print(", ".join(args), end="")
print(") \\\n (", end="")
if i == 2:
print("((v) == (a)) || ((v) == (b))", end="")
else:
print("_VA_ELEM%d(v, %s) || ((v) == (%s))" % (i, ", ".join(args[:-1]), args[-1]), end="")
print(")")
【讨论】:
以上是关于用于 C 的 Varargs `ELEM` 宏的主要内容,如果未能解决你的问题,请参考以下文章
C语言函数参数中的三个点(三点 “...”)是干什么用的?(可变参数)<stdarg.h>va_start 宏va_arg 宏va_end 宏
C语言函数参数中的三个点(三点 “...”)是干什么用的?(可变参数)<stdarg.h>va_start 宏va_arg 宏va_end 宏