是否有可能防止C中宏的重复,相同的参数?

在某些罕见的情况下,防止宏的重复参数可能很有用。

拿这个ELEM(value, ...)宏,

检查valueAB还是C

 if (ELEM(value, A, B, C)) { .... } 

有人可能偶然会多次传入相同的参数,例如:

 if (ELEM(value, A, B, B)) { .... } 

虽然有效的C,但几乎肯定是一个意外,并且极不可能是开发人员的意图。

……这当然是一个微不足道的例子,实际的错误案例会更复杂。

有没有办法让编译器发出警告/错误
传递重复参数时?


澄清:

  • 参数不一定所有常量(它们也可以与变量混合)。

笔记…

  • 问,因为这是我最近在一些代码中发现的实际错误。
    虽然有限制宏/编译器可以防止出错,但如果宏不允许,可能会提前检测到。
    当然这些错误应该在代码审查中找到……
    然而,错误发生了。

  • 这可能必须使用一些GCC /编译器特定的扩展,例如__builtin_constant_p

  • 执行此操作的一种方法(这不是简单的certificate,但有助于避免一些错误) ,可能是将标识符转换为字符串,然后静态断言,如果任何标识符是完全匹配。
    具有明显的缺点,即不同的标识符可以表示相同的常数值。 也可以写入相同的标识符以便不进行比较,例如: A[0]A[ 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标准的一部分,您也可以使用assert.h定义的static_assert

此方法通过比较标识符并在编译时失败(如果它们不符合我们的要求)。

它并不完全是万无一失的,因为2个参数可能实际上是相同的,但在转换为字符串标识符时不匹配。 然而,它将抓住最常见的错误。


请注意,虽然这确实有效 ,但我不确定是否会将其提交到生产代码中,因为它依赖于一些非常复杂的宏并且显着减慢编译速度(至少在我自己的测试中使用gcc)


链接到单个文件示例。

示例,输出:

 Found! Strings match? 0 Strings match? 1 Strings match? 0 Strings match? 1 

C档案:

 #include  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) xy #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测试