某些罕见的案例,防止宏的重复参数可能会有用。
获取此ELEM(value, ...)
宏,
要检查value
是A
,B
还是C
。
if (ELEM(value, A, B, C)) { .... }
有人可能偶然会多次传递相同的参数,例如:
if (ELEM(value, A, B, B)) { .... }
虽然有效的C,但几乎肯定是一个意外,并且极不可能成为开发人员的意图。
...这当然是一个微不足道的例子,实际的错误案例会更复杂。
在传递重复参数时,有没有办法让编译器发出警告/错误信号?
澄清:
...注释
问,因为这是我最近在一些代码中发现的实际错误。
虽然有限制宏/编译器可以防止错误,但如果宏不允许,可能会提前检测到当然,这些错误应该在代码审查中找到......然而,错误发生了。
这可能必须使用某些GCC /编译器特定的扩展名,例如__builtin_constant_p
。
一种方法(这不是万无一失但有助于避免一些错误),
可以将标识符转换为字符串,然后如果任何标识符是完全匹配则静态断言。
具有明显的缺点,即不同的标识符可以表示相同的常量值。也可以编写相同的标识符以便不进行比较,例如:A[0]
vs A[ 0 ]
。
如果预处理器/编译器不能轻易做到这一点,那么后退解决方案可能是做一些基本的静态检查工具。
答案 0 :(得分:0)
请尝试以下操作,不确定这是标准C还是gcc扩展名。
#define MAC(a,b,c) _Static_assert(a != b, "must not be equal to b")
int main()
{
MAC(2,1,0);
MAC(1,1,0);
}
修改:这是C11标准的一部分,您也可以使用static_assert
中定义的assert.h
答案 1 :(得分:0)
此方法通过比较标识符并在编译时失败,如果它们不符合我们的要求。
这并不完全是万无一失的,因为2个参数可能实际上相同,但在转换为字符串标识符时不匹配。然而,它将捕捉到最常见的错误。
请注意,虽然确实有效,但我不确定是否会将此提交到生产代码中,因为它依赖于一些非常复杂的宏并且显着减慢了编译速度(在我自己的测试中)至少gcc)。
示例,输出:
Found!
Strings match? 0
Strings match? 1
Strings match? 0
Strings match? 1
C档案:
#include <stdio.h>
int main(void)
{
int a = 1;
int A = 0, B = 1, C = 2, D = 3;
STATIC_ASSERT(!PP_ID_EQ(FOO, BAR));
STATIC_ASSERT(UNIQUE(A, B, C, D));
if (ELEM(a, A, B, C)) printf("Found!\n");
/* uncomment will fail to compile */
// STATIC_ASSERT(!PP_ID_EQ(MATCH, MATCH));
// STATIC_ASSERT(UNIQUE(D, A, B, C, D));
// if (ELEM(a, A, B, B)) printf("Found!\n");
printf("Strings match? %d\n", PP_ID_EQ(FOO, BAR));
printf("Strings match? %d\n", PP_ID_EQ(BAR, BAR));
printf("Strings match? %d\n", PP_STR_EQ("HELLO", "WORLD"));
printf("Strings match? %d\n", PP_STR_EQ("WORLD", "WORLD"));
}
C标题:
/**
* Script to generate...
* \code{.py}
* MAX = 64
* for i in range(1, MAX):
* if i == 1:
* print('#define _PP_STRCMP_%d(a, b) ((a)[1] == (b)[1])' % (i,))
* else:
* print('#define _PP_STRCMP_%d(a, b) _PP_STRCMP_%d(a, b) && ((a)[%d] == (b)[%d])' % (i, i - 1, i, i))
* \endcode
*/
#define _PP_STRCMP_1(a, b) ((a)[1] == (b)[1])
#define _PP_STRCMP_2(a, b) _PP_STRCMP_1(a, b) && ((a)[2] == (b)[2])
#define _PP_STRCMP_3(a, b) _PP_STRCMP_2(a, b) && ((a)[3] == (b)[3])
#define _PP_STRCMP_4(a, b) _PP_STRCMP_3(a, b) && ((a)[4] == (b)[4])
#define _PP_STRCMP_5(a, b) _PP_STRCMP_4(a, b) && ((a)[5] == (b)[5])
#define _PP_STRCMP_6(a, b) _PP_STRCMP_5(a, b) && ((a)[6] == (b)[6])
#define _PP_STRCMP_7(a, b) _PP_STRCMP_6(a, b) && ((a)[7] == (b)[7])
#define _PP_STRCMP_8(a, b) _PP_STRCMP_7(a, b) && ((a)[8] == (b)[8])
#define _PP_STRCMP_9(a, b) _PP_STRCMP_8(a, b) && ((a)[9] == (b)[9])
#define _PP_STRCMP_10(a, b) _PP_STRCMP_9(a, b) && ((a)[10] == (b)[10])
#define _PP_STRCMP_11(a, b) _PP_STRCMP_10(a, b) && ((a)[11] == (b)[11])
#define _PP_STRCMP_12(a, b) _PP_STRCMP_11(a, b) && ((a)[12] == (b)[12])
#define _PP_STRCMP_13(a, b) _PP_STRCMP_12(a, b) && ((a)[13] == (b)[13])
#define _PP_STRCMP_14(a, b) _PP_STRCMP_13(a, b) && ((a)[14] == (b)[14])
#define _PP_STRCMP_15(a, b) _PP_STRCMP_14(a, b) && ((a)[15] == (b)[15])
#define _PP_STRCMP_16(a, b) _PP_STRCMP_15(a, b) && ((a)[16] == (b)[16])
#define _PP_STRCMP_17(a, b) _PP_STRCMP_16(a, b) && ((a)[17] == (b)[17])
#define _PP_STRCMP_18(a, b) _PP_STRCMP_17(a, b) && ((a)[18] == (b)[18])
#define _PP_STRCMP_19(a, b) _PP_STRCMP_18(a, b) && ((a)[19] == (b)[19])
#define _PP_STRCMP_20(a, b) _PP_STRCMP_19(a, b) && ((a)[20] == (b)[20])
#define _PP_STRCMP_21(a, b) _PP_STRCMP_20(a, b) && ((a)[21] == (b)[21])
#define _PP_STRCMP_22(a, b) _PP_STRCMP_21(a, b) && ((a)[22] == (b)[22])
#define _PP_STRCMP_23(a, b) _PP_STRCMP_22(a, b) && ((a)[23] == (b)[23])
#define _PP_STRCMP_24(a, b) _PP_STRCMP_23(a, b) && ((a)[24] == (b)[24])
#define _PP_STRCMP_25(a, b) _PP_STRCMP_24(a, b) && ((a)[25] == (b)[25])
#define _PP_STRCMP_26(a, b) _PP_STRCMP_25(a, b) && ((a)[26] == (b)[26])
#define _PP_STRCMP_27(a, b) _PP_STRCMP_26(a, b) && ((a)[27] == (b)[27])
#define _PP_STRCMP_28(a, b) _PP_STRCMP_27(a, b) && ((a)[28] == (b)[28])
#define _PP_STRCMP_29(a, b) _PP_STRCMP_28(a, b) && ((a)[29] == (b)[29])
#define _PP_STRCMP_30(a, b) _PP_STRCMP_29(a, b) && ((a)[30] == (b)[30])
#define _PP_STRCMP_31(a, b) _PP_STRCMP_30(a, b) && ((a)[31] == (b)[31])
#define _PP_STRCMP_32(a, b) _PP_STRCMP_31(a, b) && ((a)[32] == (b)[32])
#define _PP_STRCMP_33(a, b) _PP_STRCMP_32(a, b) && ((a)[33] == (b)[33])
#define _PP_STRCMP_34(a, b) _PP_STRCMP_33(a, b) && ((a)[34] == (b)[34])
#define _PP_STRCMP_35(a, b) _PP_STRCMP_34(a, b) && ((a)[35] == (b)[35])
#define _PP_STRCMP_36(a, b) _PP_STRCMP_35(a, b) && ((a)[36] == (b)[36])
#define _PP_STRCMP_37(a, b) _PP_STRCMP_36(a, b) && ((a)[37] == (b)[37])
#define _PP_STRCMP_38(a, b) _PP_STRCMP_37(a, b) && ((a)[38] == (b)[38])
#define _PP_STRCMP_39(a, b) _PP_STRCMP_38(a, b) && ((a)[39] == (b)[39])
#define _PP_STRCMP_40(a, b) _PP_STRCMP_39(a, b) && ((a)[40] == (b)[40])
#define _PP_STRCMP_41(a, b) _PP_STRCMP_40(a, b) && ((a)[41] == (b)[41])
#define _PP_STRCMP_42(a, b) _PP_STRCMP_41(a, b) && ((a)[42] == (b)[42])
#define _PP_STRCMP_43(a, b) _PP_STRCMP_42(a, b) && ((a)[43] == (b)[43])
#define _PP_STRCMP_44(a, b) _PP_STRCMP_43(a, b) && ((a)[44] == (b)[44])
#define _PP_STRCMP_45(a, b) _PP_STRCMP_44(a, b) && ((a)[45] == (b)[45])
#define _PP_STRCMP_46(a, b) _PP_STRCMP_45(a, b) && ((a)[46] == (b)[46])
#define _PP_STRCMP_47(a, b) _PP_STRCMP_46(a, b) && ((a)[47] == (b)[47])
#define _PP_STRCMP_48(a, b) _PP_STRCMP_47(a, b) && ((a)[48] == (b)[48])
#define _PP_STRCMP_49(a, b) _PP_STRCMP_48(a, b) && ((a)[49] == (b)[49])
#define _PP_STRCMP_50(a, b) _PP_STRCMP_49(a, b) && ((a)[50] == (b)[50])
#define _PP_STRCMP_51(a, b) _PP_STRCMP_50(a, b) && ((a)[51] == (b)[51])
#define _PP_STRCMP_52(a, b) _PP_STRCMP_51(a, b) && ((a)[52] == (b)[52])
#define _PP_STRCMP_53(a, b) _PP_STRCMP_52(a, b) && ((a)[53] == (b)[53])
#define _PP_STRCMP_54(a, b) _PP_STRCMP_53(a, b) && ((a)[54] == (b)[54])
#define _PP_STRCMP_55(a, b) _PP_STRCMP_54(a, b) && ((a)[55] == (b)[55])
#define _PP_STRCMP_56(a, b) _PP_STRCMP_55(a, b) && ((a)[56] == (b)[56])
#define _PP_STRCMP_57(a, b) _PP_STRCMP_56(a, b) && ((a)[57] == (b)[57])
#define _PP_STRCMP_58(a, b) _PP_STRCMP_57(a, b) && ((a)[58] == (b)[58])
#define _PP_STRCMP_59(a, b) _PP_STRCMP_58(a, b) && ((a)[59] == (b)[59])
#define _PP_STRCMP_60(a, b) _PP_STRCMP_59(a, b) && ((a)[60] == (b)[60])
#define _PP_STRCMP_61(a, b) _PP_STRCMP_60(a, b) && ((a)[61] == (b)[61])
#define _PP_STRCMP_62(a, b) _PP_STRCMP_61(a, b) && ((a)[62] == (b)[62])
#define _PP_STRCMP_63(a, b) _PP_STRCMP_62(a, b) && ((a)[63] == (b)[63])
/**
* Strings must be constant and NULL terminated.
*
* Script to generate...
* \code{.py}
* MAX = 64
* print('#define PP_STR_EQ(a, b) ( \\')
* print(' (sizeof(int[(sizeof(a) > %d ? -1 : 1)])) && \\' % MAX)
* print(' (sizeof(a) == sizeof(b)) && \\')
* print(' (((sizeof(a) == 1)) || \\')
* for i in range(2, MAX + 1):
* print(' ((sizeof(a) == %d) && _PP_STRCMP_%d(a, b)) %s' % (i, i - 1, "|| \\" if i != MAX else "))"))
* \endcode
*/
#define PP_STR_EQ(a, b) ( \
(sizeof(int[(sizeof(a) > 64 ? -1 : 1)])) && \
(sizeof(a) == sizeof(b)) && \
(((sizeof(a) == 1)) || \
((sizeof(a) == 2) && _PP_STRCMP_1(a, b)) || \
((sizeof(a) == 3) && _PP_STRCMP_2(a, b)) || \
((sizeof(a) == 4) && _PP_STRCMP_3(a, b)) || \
((sizeof(a) == 5) && _PP_STRCMP_4(a, b)) || \
((sizeof(a) == 6) && _PP_STRCMP_5(a, b)) || \
((sizeof(a) == 7) && _PP_STRCMP_6(a, b)) || \
((sizeof(a) == 8) && _PP_STRCMP_7(a, b)) || \
((sizeof(a) == 9) && _PP_STRCMP_8(a, b)) || \
((sizeof(a) == 10) && _PP_STRCMP_9(a, b)) || \
((sizeof(a) == 11) && _PP_STRCMP_10(a, b)) || \
((sizeof(a) == 12) && _PP_STRCMP_11(a, b)) || \
((sizeof(a) == 13) && _PP_STRCMP_12(a, b)) || \
((sizeof(a) == 14) && _PP_STRCMP_13(a, b)) || \
((sizeof(a) == 15) && _PP_STRCMP_14(a, b)) || \
((sizeof(a) == 16) && _PP_STRCMP_15(a, b)) || \
((sizeof(a) == 17) && _PP_STRCMP_16(a, b)) || \
((sizeof(a) == 18) && _PP_STRCMP_17(a, b)) || \
((sizeof(a) == 19) && _PP_STRCMP_18(a, b)) || \
((sizeof(a) == 20) && _PP_STRCMP_19(a, b)) || \
((sizeof(a) == 21) && _PP_STRCMP_20(a, b)) || \
((sizeof(a) == 22) && _PP_STRCMP_21(a, b)) || \
((sizeof(a) == 23) && _PP_STRCMP_22(a, b)) || \
((sizeof(a) == 24) && _PP_STRCMP_23(a, b)) || \
((sizeof(a) == 25) && _PP_STRCMP_24(a, b)) || \
((sizeof(a) == 26) && _PP_STRCMP_25(a, b)) || \
((sizeof(a) == 27) && _PP_STRCMP_26(a, b)) || \
((sizeof(a) == 28) && _PP_STRCMP_27(a, b)) || \
((sizeof(a) == 29) && _PP_STRCMP_28(a, b)) || \
((sizeof(a) == 30) && _PP_STRCMP_29(a, b)) || \
((sizeof(a) == 31) && _PP_STRCMP_30(a, b)) || \
((sizeof(a) == 32) && _PP_STRCMP_31(a, b)) || \
((sizeof(a) == 33) && _PP_STRCMP_32(a, b)) || \
((sizeof(a) == 34) && _PP_STRCMP_33(a, b)) || \
((sizeof(a) == 35) && _PP_STRCMP_34(a, b)) || \
((sizeof(a) == 36) && _PP_STRCMP_35(a, b)) || \
((sizeof(a) == 37) && _PP_STRCMP_36(a, b)) || \
((sizeof(a) == 38) && _PP_STRCMP_37(a, b)) || \
((sizeof(a) == 39) && _PP_STRCMP_38(a, b)) || \
((sizeof(a) == 40) && _PP_STRCMP_39(a, b)) || \
((sizeof(a) == 41) && _PP_STRCMP_40(a, b)) || \
((sizeof(a) == 42) && _PP_STRCMP_41(a, b)) || \
((sizeof(a) == 43) && _PP_STRCMP_42(a, b)) || \
((sizeof(a) == 44) && _PP_STRCMP_43(a, b)) || \
((sizeof(a) == 45) && _PP_STRCMP_44(a, b)) || \
((sizeof(a) == 46) && _PP_STRCMP_45(a, b)) || \
((sizeof(a) == 47) && _PP_STRCMP_46(a, b)) || \
((sizeof(a) == 48) && _PP_STRCMP_47(a, b)) || \
((sizeof(a) == 49) && _PP_STRCMP_48(a, b)) || \
((sizeof(a) == 50) && _PP_STRCMP_49(a, b)) || \
((sizeof(a) == 51) && _PP_STRCMP_50(a, b)) || \
((sizeof(a) == 52) && _PP_STRCMP_51(a, b)) || \
((sizeof(a) == 53) && _PP_STRCMP_52(a, b)) || \
((sizeof(a) == 54) && _PP_STRCMP_53(a, b)) || \
((sizeof(a) == 55) && _PP_STRCMP_54(a, b)) || \
((sizeof(a) == 56) && _PP_STRCMP_55(a, b)) || \
((sizeof(a) == 57) && _PP_STRCMP_56(a, b)) || \
((sizeof(a) == 58) && _PP_STRCMP_57(a, b)) || \
((sizeof(a) == 59) && _PP_STRCMP_58(a, b)) || \
((sizeof(a) == 60) && _PP_STRCMP_59(a, b)) || \
((sizeof(a) == 61) && _PP_STRCMP_60(a, b)) || \
((sizeof(a) == 62) && _PP_STRCMP_61(a, b)) || \
((sizeof(a) == 63) && _PP_STRCMP_62(a, b)) || \
((sizeof(a) == 64) && _PP_STRCMP_63(a, b)) ))
/* -------------------------------------------------------------------- */
#define STRINGIFY_ARG(x) "" #x
#define STRINGIFY_APPEND(a, b) "" a #b
#define STRINGIFY(x) STRINGIFY_APPEND("", x)
#define PP_ID_EQ(a, b) \
PP_STR_EQ(STRINGIFY(a), STRINGIFY(b))
#define STATIC_ASSERT(expr) \
((void)sizeof(int[(expr) ? 1 : -1]))
/* -------------------------------------------------------------------- */
/* varargs macros (keep first so others can use) */
/* --- 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_, \
_17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, \
_33_, _34_, _35_, _36_, _37_, _38_, _39_, _40_, _41_, _42_, _43_, _44_, _45_, _46_, _47_, _48_, \
_49_, _50_, _51_, _52_, _53_, _54_, _55_, _56_, _57_, _58_, _59_, _60_, _61_, _62_, _63_, _64_, \
count, ...) count
#define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args
/* 64 args max */
#define _VA_NARGS_COUNT(...) _VA_NARGS_EXPAND((__VA_ARGS__, \
64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, \
48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, \
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
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(__VA_ARGS__)), (__VA_ARGS__))
/* -------------------------------------------------------------------- */
/* UNIQUE#(v, ...): are all args unique?
*
* Script to generate...
* \code{.py}
* for i in range(1, 16):
* args = [(chr(ord('a') + (c % 26)) + (chr(ord('0') + (c // 26)))) for c in range(i + 1)]
* print("#define _VA_UNIQUE%d(%s) \\" % (i + 1, ", ".join(args)))
* if i > 1:
* expr = ["_VA_UNIQUE%d(%s)" % (i, ", ".join(args[:-1]))]
* else:
* expr = []
* for j in range(len(args) - 1):
* expr.append("!PP_ID_EQ(%s, %s)" % (args[j], args[-1]))
* print(" (" + " && ".join(expr) + ")")
* \endcode
*/
#define _VA_UNIQUE2(a0, b0) \
(!PP_ID_EQ(a0, b0))
#define _VA_UNIQUE3(a0, b0, c0) \
(_VA_UNIQUE2(a0, b0) && !PP_ID_EQ(a0, c0) && !PP_ID_EQ(b0, c0))
#define _VA_UNIQUE4(a0, b0, c0, d0) \
(_VA_UNIQUE3(a0, b0, c0) && !PP_ID_EQ(a0, d0) && \
!PP_ID_EQ(b0, d0) && !PP_ID_EQ(c0, d0))
#define _VA_UNIQUE5(a0, b0, c0, d0, e0) \
(_VA_UNIQUE4(a0, b0, c0, d0) && !PP_ID_EQ(a0, e0) && \
!PP_ID_EQ(b0, e0) && !PP_ID_EQ(c0, e0) && !PP_ID_EQ(d0, e0))
#define _VA_UNIQUE6(a0, b0, c0, d0, e0, f0) \
(_VA_UNIQUE5(a0, b0, c0, d0, e0) && !PP_ID_EQ(a0, f0) && \
!PP_ID_EQ(b0, f0) && !PP_ID_EQ(c0, f0) && !PP_ID_EQ(d0, f0) && !PP_ID_EQ(e0, f0))
#define _VA_UNIQUE7(a0, b0, c0, d0, e0, f0, g0) \
(_VA_UNIQUE6(a0, b0, c0, d0, e0, f0) && !PP_ID_EQ(a0, g0) && \
!PP_ID_EQ(b0, g0) && !PP_ID_EQ(c0, g0) && !PP_ID_EQ(d0, g0) && !PP_ID_EQ(e0, g0) && \
!PP_ID_EQ(f0, g0))
#define _VA_UNIQUE8(a0, b0, c0, d0, e0, f0, g0, h0) \
(_VA_UNIQUE7(a0, b0, c0, d0, e0, f0, g0) && !PP_ID_EQ(a0, h0) && \
!PP_ID_EQ(b0, h0) && !PP_ID_EQ(c0, h0) && !PP_ID_EQ(d0, h0) && !PP_ID_EQ(e0, h0) && \
!PP_ID_EQ(f0, h0) && !PP_ID_EQ(g0, h0))
#define _VA_UNIQUE9(a0, b0, c0, d0, e0, f0, g0, h0, i0) \
(_VA_UNIQUE8(a0, b0, c0, d0, e0, f0, g0, h0) && !PP_ID_EQ(a0, i0) && \
!PP_ID_EQ(b0, i0) && !PP_ID_EQ(c0, i0) && !PP_ID_EQ(d0, i0) && !PP_ID_EQ(e0, i0) && \
!PP_ID_EQ(f0, i0) && !PP_ID_EQ(g0, i0) && !PP_ID_EQ(h0, i0))
#define _VA_UNIQUE10(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0) \
(_VA_UNIQUE9(a0, b0, c0, d0, e0, f0, g0, h0, i0) && !PP_ID_EQ(a0, j0) && \
!PP_ID_EQ(b0, j0) && !PP_ID_EQ(c0, j0) && !PP_ID_EQ(d0, j0) && !PP_ID_EQ(e0, j0) && \
!PP_ID_EQ(f0, j0) && !PP_ID_EQ(g0, j0) && !PP_ID_EQ(h0, j0) && !PP_ID_EQ(i0, j0))
#define _VA_UNIQUE11(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0) \
(_VA_UNIQUE10(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0) && !PP_ID_EQ(a0, k0) && \
!PP_ID_EQ(b0, k0) && !PP_ID_EQ(c0, k0) && !PP_ID_EQ(d0, k0) && !PP_ID_EQ(e0, k0) && \
!PP_ID_EQ(f0, k0) && !PP_ID_EQ(g0, k0) && !PP_ID_EQ(h0, k0) && !PP_ID_EQ(i0, k0) && \
!PP_ID_EQ(j0, k0))
#define _VA_UNIQUE12(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0) \
(_VA_UNIQUE11(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0) && !PP_ID_EQ(a0, l0) && \
!PP_ID_EQ(b0, l0) && !PP_ID_EQ(c0, l0) && !PP_ID_EQ(d0, l0) && !PP_ID_EQ(e0, l0) && \
!PP_ID_EQ(f0, l0) && !PP_ID_EQ(g0, l0) && !PP_ID_EQ(h0, l0) && !PP_ID_EQ(i0, l0) && \
!PP_ID_EQ(j0, l0) && !PP_ID_EQ(k0, l0))
#define _VA_UNIQUE13(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0) \
(_VA_UNIQUE12(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0) && !PP_ID_EQ(a0, m0) && \
!PP_ID_EQ(b0, m0) && !PP_ID_EQ(c0, m0) && !PP_ID_EQ(d0, m0) && !PP_ID_EQ(e0, m0) && \
!PP_ID_EQ(f0, m0) && !PP_ID_EQ(g0, m0) && !PP_ID_EQ(h0, m0) && !PP_ID_EQ(i0, m0) && \
!PP_ID_EQ(j0, m0) && !PP_ID_EQ(k0, m0) && !PP_ID_EQ(l0, m0))
#define _VA_UNIQUE14(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0) \
(_VA_UNIQUE13(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0) && !PP_ID_EQ(a0, n0) && \
!PP_ID_EQ(b0, n0) && !PP_ID_EQ(c0, n0) && !PP_ID_EQ(d0, n0) && !PP_ID_EQ(e0, n0) && \
!PP_ID_EQ(f0, n0) && !PP_ID_EQ(g0, n0) && !PP_ID_EQ(h0, n0) && !PP_ID_EQ(i0, n0) && \
!PP_ID_EQ(j0, n0) && !PP_ID_EQ(k0, n0) && !PP_ID_EQ(l0, n0) && !PP_ID_EQ(m0, n0))
#define _VA_UNIQUE15(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0) \
(_VA_UNIQUE14(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0) && !PP_ID_EQ(a0, o0) && \
!PP_ID_EQ(b0, o0) && !PP_ID_EQ(c0, o0) && !PP_ID_EQ(d0, o0) && !PP_ID_EQ(e0, o0) && \
!PP_ID_EQ(f0, o0) && !PP_ID_EQ(g0, o0) && !PP_ID_EQ(h0, o0) && !PP_ID_EQ(i0, o0) && \
!PP_ID_EQ(j0, o0) && !PP_ID_EQ(k0, o0) && !PP_ID_EQ(l0, o0) && !PP_ID_EQ(m0, o0) && \
!PP_ID_EQ(n0, o0))
#define _VA_UNIQUE16(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0) \
(_VA_UNIQUE15(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0) && !PP_ID_EQ(a0, p0) && \
!PP_ID_EQ(b0, p0) && !PP_ID_EQ(c0, p0) && !PP_ID_EQ(d0, p0) && !PP_ID_EQ(e0, p0) && \
!PP_ID_EQ(f0, p0) && !PP_ID_EQ(g0, p0) && !PP_ID_EQ(h0, p0) && !PP_ID_EQ(i0, p0) && \
!PP_ID_EQ(j0, p0) && !PP_ID_EQ(k0, p0) && !PP_ID_EQ(l0, p0) && !PP_ID_EQ(m0, p0) && \
!PP_ID_EQ(n0, p0) && !PP_ID_EQ(o0, p0))
/* reusable UNIQUE macro */
#define UNIQUE(...) VA_NARGS_CALL_OVERLOAD(_VA_UNIQUE, __VA_ARGS__)
/* -------------------------------------------------------------------- */
/* ELEM#(v, ...): is the first arg equal any others? */
/* internal helpers*/
#define _VA_ELEM2(v, a) \
((v) == (a))
#define _VA_ELEM3(v, a, b) \
(_VA_ELEM2(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(...) ((void)(sizeof(int[UNIQUE(__VA_ARGS__) ? 1 : -1])), \
VA_NARGS_CALL_OVERLOAD(_VA_ELEM, __VA_ARGS__))
使用gcc5.2进行测试