2

I was wondering if theres an ELEM comparison macro in general use, where:

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

Can be replaced with:

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 end up needing to define multiple macros with argument counts.

Using a simple python script I came up with this:

 #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 in common use which accept a variable number of arguments and are at least portable enough to work with popular C compilers (GCC, Clang, Intel, MCVC).

0

Based on the answer to this question, I have a varargs ELEM macro I think works quite portably, though it depends on __VA_ARGS__ but dont think that can be helped.

Example use:

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) 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;
}

Note, _VA_ELEM# generated with 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(")")

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.