Varargs `ELEM` macro for use with C

后端 未结 1 1435
逝去的感伤
逝去的感伤 2020-12-04 02:45

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

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

Can be replaced with:

EL

相关标签:
1条回答
  • 2020-12-04 03:42

    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(")")
    
    0 讨论(0)
提交回复
热议问题