-2

在 C 中,它的常见做法是......

enum {
    A,
    B,
    C,
};

但是,对于标志,您需要明确定义它们......

enum {
    A = (1 << 0),
    B = (1 << 1),
    C = (1 << 2),
};

是否可以在不必显式列出每个值的情况下定义标志?

自从发布这个问题以来,似乎对你为什么要这样做感到有些困惑。需要明确的是,明确定义标志通常是一件“好事”,所以我的问题是关于一些相当模糊的极端情况,当你可能想避免它时。


注意:这假设标志只是“插槽”,它们从未写入磁盘或以持久方式使用,这会破坏 API 和网络协议。等等

这样做的能力可以排除一小类错误,其中......

  • 枚举标志值必须使用连续位。
  • 枚举标志位不得重叠

添加/删除位的好处是不需要更改该enum标识符之后的每个值。

诚然,这不是您一直想要使用的功能。但是在某些极端情况下它很有用。


现有解决方案(不满意)

注意到现有的(糟糕的)解决方案,这些解决方案在某种程度上有效但不满意(这就是我问这个问题的原因)

使用 2 个枚举

它有效,但与直接定义标志相比没有显着优势。

    enum {
        A_SHIFT,
        B_SHIFT,
        C_SHIFT,
    };

    enum {
        A = (1 << A_SHIFT),
        B = (1 << B_SHIFT),
        C = (1 << C_SHIFT),
    };

使用 GCC 的__COUNTER__

主要缺点是它只适用于 GCC,并且依赖于定义一些唯一的起始值来使用枚举......这会污染名称空间。

#define ENUM_INC (1 << (__COUNTER__ - _FIRST))
    enum { _FIRST = __COUNTER__ + 1 };
    enum {
        A = ENUM_INC,
        B = ENUM_INC,
        C = ENUM_INC,
    };
#undef ENUM_INC
4

2 回答 2

4

如果您愿意超越纯 C,您可以使用预处理过滤器为您生成一些代码。

例如,这是一个简单的 Perl 脚本:

#!/usr/bin/perl

use strict;
use warnings;

my $flag_bit = 0;

while (<>) {
    if (/\@RESET_FLAG\@/) {
        s/\@RESET_FLAG\@//;
        $flag_bit = 0;
    }
    elsif (/\@FLAG\@/) {
        s/\@FLAG\@/sprintf("0x%x", 1 << $flag_bit)/e;
        $flag_bit ++;
    }
    print;
}

这意味着:

enum foo {
    A = @FLAG@,
    B = @FLAG@,
    C = @FLAG@,
};

对此:

enum foo {
    A = 0x1,
    B = 0x2,
    C = 0x4,
};

@RESET_FLAG@如果您想将其与多个枚举类型一起使用,则此示例中未使用的语法允许您重置标志值。

您可以将其包含在您的构建过程中,例如,命名您的 C 源文件foo.c.in,并通过在其上运行过滤器来生成foo.cfoo.c.in

请注意,过滤器在一行中不能处理超过一次的使用,@...@如果标志的数量超过 Perl 认为的整数位数,它的行为就不会很好。它还@FLAG@在注释(应该不是问题)和字符串文字(可能是)中扩展。钟声、口哨声和错误检查留作练习。

于 2015-02-13T23:33:56.067 回答
2

使用下面的宏,您可以做到这一点。

enum { ENUM_FLAGS(A, B, C) };

虽然宏相当冗长,但调用它却不是,这可能是在构建时生成标头的合理替代方案。

适用于现代编译器 - GCC/Clang/MSVC/IntelC++。


/** generated with:
 * \code{.py}
 * enum_flag_bits = 32
 * for i in range(enum_flag_bits):
 *     args = [(chr(ord('a') + (c % 26)) + (chr(ord('0') + (c // 26)))) for c in range(i + 1)]
 *     print("#define _VA_ENUM_FLAGS_%d(%s) \\\n        " % (i + 1, ", ".join(args)), end="")
 *     if i != 0:
 *         print("_VA_ENUM_FLAGS_%d(%s) " % (i, ", ".join(args[:-1])), end="")
 *     print("%s = %s," % (args[-1], "(1u << %d)" % i))
 * \endcode
 */
#define _VA_ENUM_FLAGS_1(a0) \
        a0 = (1u << 0),
#define _VA_ENUM_FLAGS_2(a0, b0) \
        _VA_ENUM_FLAGS_1(a0) b0 = (1u << 1),
#define _VA_ENUM_FLAGS_3(a0, b0, c0) \
        _VA_ENUM_FLAGS_2(a0, b0) c0 = (1u << 2),
#define _VA_ENUM_FLAGS_4(a0, b0, c0, d0) \
        _VA_ENUM_FLAGS_3(a0, b0, c0) d0 = (1u << 3),
#define _VA_ENUM_FLAGS_5(a0, b0, c0, d0, e0) \
        _VA_ENUM_FLAGS_4(a0, b0, c0, d0) e0 = (1u << 4),
#define _VA_ENUM_FLAGS_6(a0, b0, c0, d0, e0, f0) \
        _VA_ENUM_FLAGS_5(a0, b0, c0, d0, e0) f0 = (1u << 5),
#define _VA_ENUM_FLAGS_7(a0, b0, c0, d0, e0, f0, g0) \
        _VA_ENUM_FLAGS_6(a0, b0, c0, d0, e0, f0) g0 = (1u << 6),
#define _VA_ENUM_FLAGS_8(a0, b0, c0, d0, e0, f0, g0, h0) \
        _VA_ENUM_FLAGS_7(a0, b0, c0, d0, e0, f0, g0) h0 = (1u << 7),
#define _VA_ENUM_FLAGS_9(a0, b0, c0, d0, e0, f0, g0, h0, i0) \
        _VA_ENUM_FLAGS_8(a0, b0, c0, d0, e0, f0, g0, h0) i0 = (1u << 8),
#define _VA_ENUM_FLAGS_10(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0) \
        _VA_ENUM_FLAGS_9(a0, b0, c0, d0, e0, f0, g0, h0, i0) j0 = (1u << 9),
#define _VA_ENUM_FLAGS_11(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0) \
        _VA_ENUM_FLAGS_10(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0) k0 = (1u << 10),
#define _VA_ENUM_FLAGS_12(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0) \
        _VA_ENUM_FLAGS_11(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0) l0 = (1u << 11),
#define _VA_ENUM_FLAGS_13(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0) \
        _VA_ENUM_FLAGS_12(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0) m0 = (1u << 12),
#define _VA_ENUM_FLAGS_14(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0) \
        _VA_ENUM_FLAGS_13(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0) n0 = (1u << 13),
#define _VA_ENUM_FLAGS_15(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0) \
        _VA_ENUM_FLAGS_14(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0) o0 = (1u << 14),
#define _VA_ENUM_FLAGS_16(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0) \
        _VA_ENUM_FLAGS_15(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0) p0 = (1u << 15),
#define _VA_ENUM_FLAGS_17(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0) \
        _VA_ENUM_FLAGS_16(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0) q0 = (1u << 16),
#define _VA_ENUM_FLAGS_18(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0) \
        _VA_ENUM_FLAGS_17(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0) r0 = (1u << 17),
#define _VA_ENUM_FLAGS_19(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0) \
        _VA_ENUM_FLAGS_18(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0) s0 = (1u << 18),
#define _VA_ENUM_FLAGS_20(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0) \
        _VA_ENUM_FLAGS_19(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0) t0 = (1u << 19),
#define _VA_ENUM_FLAGS_21(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0) \
        _VA_ENUM_FLAGS_20(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0) u0 = (1u << 20),
#define _VA_ENUM_FLAGS_22(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0) \
        _VA_ENUM_FLAGS_21(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0) v0 = (1u << 21),
#define _VA_ENUM_FLAGS_23(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0) \
        _VA_ENUM_FLAGS_22(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0) w0 = (1u << 22),
#define _VA_ENUM_FLAGS_24(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0) \
        _VA_ENUM_FLAGS_23(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0) x0 = (1u << 23),
#define _VA_ENUM_FLAGS_25(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0) \
        _VA_ENUM_FLAGS_24(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0) y0 = (1u << 24),
#define _VA_ENUM_FLAGS_26(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0, z0) \
        _VA_ENUM_FLAGS_25(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0) z0 = (1u << 25),
#define _VA_ENUM_FLAGS_27(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0, z0, a1) \
        _VA_ENUM_FLAGS_26(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0, z0) a1 = (1u << 26),
#define _VA_ENUM_FLAGS_28(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0, z0, a1, b1) \
        _VA_ENUM_FLAGS_27(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0, z0, a1) b1 = (1u << 27),
#define _VA_ENUM_FLAGS_29(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0, z0, a1, b1, c1) \
        _VA_ENUM_FLAGS_28(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0, z0, a1, b1) c1 = (1u << 28),
#define _VA_ENUM_FLAGS_30(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0, z0, a1, b1, c1, d1) \
        _VA_ENUM_FLAGS_29(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0, z0, a1, b1, c1) d1 = (1u << 29),
#define _VA_ENUM_FLAGS_31(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1) \
        _VA_ENUM_FLAGS_30(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0, z0, a1, b1, c1, d1) e1 = (1u << 30),
#define _VA_ENUM_FLAGS_32(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1) \
        _VA_ENUM_FLAGS_31(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1) f1 = (1u << 31),

/* reusable ENUM_FLAGS macro */
#define ENUM_FLAGS(...) VA_NARGS_CALL_OVERLOAD(_VA_ENUM_FLAGS_, __VA_ARGS__)

使用这里VA_NARGS_CALL_OVERLOAD定义的:


/* 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__))
于 2015-02-13T22:12:28.813 回答