Varargs `ELEM` macro for use with C

I was wondering if in general the ELEM comparison macro is used, where:

(v == a || v == b)

Can be replaced by:

ELEM(v, a, b)

Of course, this can be done with a macro,

#define ELEM(v, a, b) (((v) == (a)) || ((v) == (b)))

However, then you need to define several macros with argument counting.

Using a simple python script, I came up with the following:

  #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))) 

From this python3- script:

 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(")") 

But I was wondering if there are any ELEM macros that take a variable number of arguments and are at least portable enough to work with the popular C compilers (GCC, Clang, Intel, MCVC).

+1
c macros c-preprocessor
Jul 19 '14 at 4:37
source share
1 answer

Based on the answer to this question , I have an ELAR varargs macro, which I think works quite portable, although it depends on __VA_ARGS__ , but I don’t think it could help.

Usage example:

 if (ELEM(var, A, B)) { .... } else if (ELEM(var, C, D, E, F, G)) { .... } 

Implimentation:

 #include <stdio.h> /* ------ */ /* Macros */ /* internal helpers */ #define _VA_NARGS_GLUE(x, y) xy #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; } 

Note, _VA_ELEM# generated using this python3- script:

 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(")") 
0
Jul 19 '14 at 5:21
source share



All Articles