如何将后续位分配给C枚举成员?

发布于 2025-02-06 18:15:48 字数 1218 浏览 3 评论 0原文

这是我得到的:

enum X {
    NONE = 0x00000000,
    FLAG_1 = 0x00000001,
    FLAG_2 = 0x00000002,
    FLAG_3 = 0x00000004,
    FLAG_4 = 0x00000008,
    FLAG_5 = 0x00000010,
    // ...
    FLAG_32 = 0x80000000
}

有没有一种方法可以使“位编号”自动变速,以便我想插入一个标志,以便下一步得到“重新编号”?

我只是在设计一个API,我想将相关标志放在一起,以特定的顺序进行订购。问题是,当我添加中间的内容时,我必须手动重新分配所有插入项目后进行的所有编号。假设在我的示例中,我想添加flag_2a = 0x00000004,而flag_3应为0x00000008,依此类推。是否有“完整的汽车”做到这一点?

好的,这是想到的第一件事:

#include <stdio.h>

enum { __FLAGS1_BASE = __COUNTER__ };
#define __FLAGS1_CT 1 << (__COUNTER__ - __FLAGS1_BASE - 1)

typedef enum __TEST1 {
    FLAG1_0 = 0,
    FLAG1_1 = __FLAGS1_CT,
    FLAG1_2 = __FLAGS1_CT,
    FLAG1_3 = __FLAGS1_CT,
    FLAG1_4 = __FLAGS1_CT
} TEST1;

enum { __FLAGS2_BASE = __COUNTER__ };
#define __FLAGS2_CT 1 << (__COUNTER__ - __FLAGS2_BASE - 1)

typedef enum __TEST2 {
    FLAG2_0 = 0,
    FLAG2_1 = __FLAGS2_CT,
    FLAG2_2 = __FLAGS2_CT,
    FLAG2_3 = __FLAGS2_CT,
    FLAG2_4 = __FLAGS2_CT
} TEST2;

int main() {
    printf("X = %u\n", FLAG2_3); // should output 4.
    return 0;
}

这是唯一的方法,还是比这简单的事情?

Here's what I got:

enum X {
    NONE = 0x00000000,
    FLAG_1 = 0x00000001,
    FLAG_2 = 0x00000002,
    FLAG_3 = 0x00000004,
    FLAG_4 = 0x00000008,
    FLAG_5 = 0x00000010,
    // ...
    FLAG_32 = 0x80000000
}

Is there a way to make "bit numbering" automatic so I could like insert a flag so all that goes next get "renumbered"?

I'm just designing an API and I want to keep related flags together, ordered in a specific sequence. The problem is when I add something that goes in the middle I have to manually reassign all numbering that goes after the inserted item. Let's say in my example I want to add FLAG_2A = 0x00000004, and FLAG_3 should be 0x00000008 and so on. Is there a "full auto" way of doing it?

OK, here's the first thing that comes to mind:

#include <stdio.h>

enum { __FLAGS1_BASE = __COUNTER__ };
#define __FLAGS1_CT 1 << (__COUNTER__ - __FLAGS1_BASE - 1)

typedef enum __TEST1 {
    FLAG1_0 = 0,
    FLAG1_1 = __FLAGS1_CT,
    FLAG1_2 = __FLAGS1_CT,
    FLAG1_3 = __FLAGS1_CT,
    FLAG1_4 = __FLAGS1_CT
} TEST1;

enum { __FLAGS2_BASE = __COUNTER__ };
#define __FLAGS2_CT 1 << (__COUNTER__ - __FLAGS2_BASE - 1)

typedef enum __TEST2 {
    FLAG2_0 = 0,
    FLAG2_1 = __FLAGS2_CT,
    FLAG2_2 = __FLAGS2_CT,
    FLAG2_3 = __FLAGS2_CT,
    FLAG2_4 = __FLAGS2_CT
} TEST2;

int main() {
    printf("X = %u\n", FLAG2_3); // should output 4.
    return 0;
}

Is it the only way, or is there something simpler than that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

那片花海 2025-02-13 18:15:48

我将make_flags宏观HolyblackCat提出的快速实现汇总了:

#define E3(...) E2(E2(E2(E2(E2(E2(E2(__VA_ARGS__)))))))
#define E2(...) E1(E1(E1(E1(E1(E1(E1(E1(__VA_ARGS__))))))))
#define E1(...) __VA_ARGS__

#define EMPTY()
#define TUPLE_AT_2(x,y,...) y

#define CHECK(...) TUPLE_AT_2(__VA_ARGS__,0,)
#define EQ_END_END ,1

#define CAT(a,b) CAT_(a,b)
#define CAT_(a,b) a##b

#define LOOP_() LOOP
#define LOOP(x,y,...) CAT(LOOP, CHECK(EQ_END_##y))(x,y,__VA_ARGS__)
#define LOOP1(x,...) 
#define LOOP0(x,y,...) y = x << 1, LOOP_ EMPTY() ()(y,__VA_ARGS__)

#define HEAD(x,...) x
#define MAKE_FLAGS(name,...) typedef enum { HEAD(__VA_ARGS__,) = 1, E3(LOOP(__VA_ARGS__, END)) } name 

MAKE_FLAGS(MyEnum, flag1, flag2, flag3, flag4);
// expands to:
// typedef enum { flag1 = 1, flag2 = flag1 << 1, flag3 = flag2 << 1, flag4 = flag3 << 1, } MyEnum;

I threw together a quick implementation of the MAKE_FLAGS macro HolyBlackCat suggested:

#define E3(...) E2(E2(E2(E2(E2(E2(E2(__VA_ARGS__)))))))
#define E2(...) E1(E1(E1(E1(E1(E1(E1(E1(__VA_ARGS__))))))))
#define E1(...) __VA_ARGS__

#define EMPTY()
#define TUPLE_AT_2(x,y,...) y

#define CHECK(...) TUPLE_AT_2(__VA_ARGS__,0,)
#define EQ_END_END ,1

#define CAT(a,b) CAT_(a,b)
#define CAT_(a,b) a##b

#define LOOP_() LOOP
#define LOOP(x,y,...) CAT(LOOP, CHECK(EQ_END_##y))(x,y,__VA_ARGS__)
#define LOOP1(x,...) 
#define LOOP0(x,y,...) y = x << 1, LOOP_ EMPTY() ()(y,__VA_ARGS__)

#define HEAD(x,...) x
#define MAKE_FLAGS(name,...) typedef enum { HEAD(__VA_ARGS__,) = 1, E3(LOOP(__VA_ARGS__, END)) } name 

MAKE_FLAGS(MyEnum, flag1, flag2, flag3, flag4);
// expands to:
// typedef enum { flag1 = 1, flag2 = flag1 << 1, flag3 = flag2 << 1, flag4 = flag3 << 1, } MyEnum;
找回味觉 2025-02-13 18:15:48

与 @chqrlie的答案(使用第二个枚举生成连续索引)相同,但使用宏生成:

#define MAKE_FLAGS(name_, zero_, seq_) \
    enum CAT(BitIndices_, name_) { END( IMPL_MAKE_FLAGS_loop1_a seq_ ) }; \
    typedef enum name_ { zero_ = 0, END( IMPL_MAKE_FLAGS_loop2_a seq_ ) } name_;

#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x##y

#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_end

#define IMPL_MAKE_FLAGS_loop1_a(name_) CAT(bitindex_, name_), IMPL_MAKE_FLAGS_loop1_b
#define IMPL_MAKE_FLAGS_loop1_b(name_) CAT(bitindex_, name_), IMPL_MAKE_FLAGS_loop1_a
#define IMPL_MAKE_FLAGS_loop1_a_end
#define IMPL_MAKE_FLAGS_loop1_b_end

#define IMPL_MAKE_FLAGS_loop2_a(name_) name_ = 1ull << CAT(bitindex_, name_), IMPL_MAKE_FLAGS_loop2_b
#define IMPL_MAKE_FLAGS_loop2_b(name_) name_ = 1ull << CAT(bitindex_, name_), IMPL_MAKE_FLAGS_loop2_a
#define IMPL_MAKE_FLAGS_loop2_a_end
#define IMPL_MAKE_FLAGS_loop2_b_end

然后make_flags(e,none,(x)(y)(z)) 展开至:

enum BitIndices_E { bitindex_x, bitindex_y, bitindex_z, };
typedef enum E
{
    none = 0,
    x = 1ull << bitindex_x,
    y = 1ull << bitindex_y,
    z = 1ull << bitindex_z,
} E;

Same idea as @chqrlie's answer (using a second enum to generate sequental indices), but generated with a macro:

#define MAKE_FLAGS(name_, zero_, seq_) \
    enum CAT(BitIndices_, name_) { END( IMPL_MAKE_FLAGS_loop1_a seq_ ) }; \
    typedef enum name_ { zero_ = 0, END( IMPL_MAKE_FLAGS_loop2_a seq_ ) } name_;

#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x##y

#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_end

#define IMPL_MAKE_FLAGS_loop1_a(name_) CAT(bitindex_, name_), IMPL_MAKE_FLAGS_loop1_b
#define IMPL_MAKE_FLAGS_loop1_b(name_) CAT(bitindex_, name_), IMPL_MAKE_FLAGS_loop1_a
#define IMPL_MAKE_FLAGS_loop1_a_end
#define IMPL_MAKE_FLAGS_loop1_b_end

#define IMPL_MAKE_FLAGS_loop2_a(name_) name_ = 1ull << CAT(bitindex_, name_), IMPL_MAKE_FLAGS_loop2_b
#define IMPL_MAKE_FLAGS_loop2_b(name_) name_ = 1ull << CAT(bitindex_, name_), IMPL_MAKE_FLAGS_loop2_a
#define IMPL_MAKE_FLAGS_loop2_a_end
#define IMPL_MAKE_FLAGS_loop2_b_end

Then MAKE_FLAGS( E, none, (x)(y)(z) ) expands to:

enum BitIndices_E { bitindex_x, bitindex_y, bitindex_z, };
typedef enum E
{
    none = 0,
    x = 1ull << bitindex_x,
    y = 1ull << bitindex_y,
    z = 1ull << bitindex_z,
} E;
你在我安 2025-02-13 18:15:48

这是一种替代方法:

enum X_bits {
    B0,  // replace Bx with actual flag name
    B1,
    B2,
    //...
    B32
};

#define FLAG(x)  FLAG_##x = 1U << x
enum X {
    NONE = 0,
    FLAG(B0),  // will define FLAG_B0 with the appropriate value 0x1
    FLAG(B1),
    FLAG(B2),
    //...
    FLAG(B32)
};

自动计算实际的位数和位标记。

Here is an alternative approach:

enum X_bits {
    B0,  // replace Bx with actual flag name
    B1,
    B2,
    //...
    B32
};

#define FLAG(x)  FLAG_##x = 1U << x
enum X {
    NONE = 0,
    FLAG(B0),  // will define FLAG_B0 with the appropriate value 0x1
    FLAG(B1),
    FLAG(B2),
    //...
    FLAG(B32)
};

Actual bit numbers and bit marks are computed automatically.

洛阳烟雨空心柳 2025-02-13 18:15:48

最好的解决方案是手动输入它,仅32行。

如果您坚持使用宏来生成它,那么最少的糟糕版本不是 与一些“聪明”人为的人为运行的版本,但要使用“ x-macros”的事实上的标准解决方案, :

#define FLAG_LIST(X) \
  X(1) X(2) X(3) X(4)  /* ... */

#define flag_decl(val) FLAG_##val = val,
#define flag_mask_decl(val) FLAG_MASK_##val = 1u << (val-1),

typedef enum 
{
  FLAG_0 = 0,
  FLAG_LIST(flag_decl)
} flag;

typedef enum 
{
  FLAG_MASK_0 = 0,
  FLAG_LIST(flag_mask_decl)
} flag_mask;

以上的前处理器输出:

typedef enum
{
  FLAG_0 = 0,
  FLAG_1 = 1, FLAG_2 = 2, FLAG_3 = 3, FLAG_4 = 4,
} flag;

typedef enum
{
  FLAG_MASK_0 = 0,
  FLAG_MASK_1 = 1u << (1 -1), FLAG_MASK_2 = 1u << (2 -1), FLAG_MASK_3 = 1u << (3 -1), FLAG_MASK_4 = 1u << (4 -1),
} flag_mask;

The best solution is to type it out manually, it's just 32 rows.

In case you insist on generating it with macros, then the least bad version is not to run amok with some "clever" contrived ones, but to go with a de facto standard solution using "x-macros":

#define FLAG_LIST(X) \
  X(1) X(2) X(3) X(4)  /* ... */

#define flag_decl(val) FLAG_##val = val,
#define flag_mask_decl(val) FLAG_MASK_##val = 1u << (val-1),

typedef enum 
{
  FLAG_0 = 0,
  FLAG_LIST(flag_decl)
} flag;

typedef enum 
{
  FLAG_MASK_0 = 0,
  FLAG_LIST(flag_mask_decl)
} flag_mask;

Pre-processor output of the above:

typedef enum
{
  FLAG_0 = 0,
  FLAG_1 = 1, FLAG_2 = 2, FLAG_3 = 3, FLAG_4 = 4,
} flag;

typedef enum
{
  FLAG_MASK_0 = 0,
  FLAG_MASK_1 = 1u << (1 -1), FLAG_MASK_2 = 1u << (2 -1), FLAG_MASK_3 = 1u << (3 -1), FLAG_MASK_4 = 1u << (4 -1),
} flag_mask;
过度放纵 2025-02-13 18:15:48

我的最后一个拍摄:flags.h头:

#pragma once

#define BIT_FLAG_BASE(base) enum { base = __COUNTER__ + 1 } ///< Sets the base for the bit flag counter.
#define BIT_FLAG(base) 1U << (__COUNTER__ - base) ///< Gets the next bit for the bit flag counter.

这样使用:

#include "flags.h"

BIT_FLAG_BASE(MyFlag);

enum MyFlags {
    B1 = BIT_FLAG(MyFlag),
    B2 = BIT_FLAG(MyFlag),
    // ...
    B31 = BIT_FLAG(MyFlag)
};

My last take: flags.h header:

#pragma once

#define BIT_FLAG_BASE(base) enum { base = __COUNTER__ + 1 } ///< Sets the base for the bit flag counter.
#define BIT_FLAG(base) 1U << (__COUNTER__ - base) ///< Gets the next bit for the bit flag counter.

Used like this:

#include "flags.h"

BIT_FLAG_BASE(MyFlag);

enum MyFlags {
    B1 = BIT_FLAG(MyFlag),
    B2 = BIT_FLAG(MyFlag),
    // ...
    B31 = BIT_FLAG(MyFlag)
};
书信已泛黄 2025-02-13 18:15:48

有多少个组合?我是一个冗长的人,我会这样:

// for i in $(seq 3); do echo "#define BITFLAG_$i(N$(printf ",_%s" $(seq $i))) \\"
\n'"enum N { \\$(seq $((i-1)) | xargs -i printf "\n\t_{} = (1 << {}), \\\\")"
\n'"};"; done
#define BITFLAG_1(N,_1) \
enum N { \
};
#define BITFLAG_2(N,_1,_2) \
enum N { \
        _1 = (1 << 1), \
};
#define BITFLAG_3(N,_1,_2,_3) \
enum N { \
        _1 = (1 << 1), \
        _2 = (1 << 2), \
};
/* etc. */
    
#define BITFLAG_N(_10,_9,_8,_7,_6,_5,_4,_3,_2,_1,_0,N,...)  BITFLAG_##N
#define BITFLAG(...)  BITFLAG_N(__VA_ARGS__,10,9,8,7,6,5,4,3,2,1)(__VA_ARGS__)

BITFLAG(
    X,
    FLAG1,
    FLAG2,
)

How many combinations are there? I am a verbose guy, I would do:

// for i in $(seq 3); do echo "#define BITFLAG_$i(N$(printf ",_%s" $(seq $i))) \\"
\n'"enum N { \\$(seq $((i-1)) | xargs -i printf "\n\t_{} = (1 << {}), \\\\")"
\n'"};"; done
#define BITFLAG_1(N,_1) \
enum N { \
};
#define BITFLAG_2(N,_1,_2) \
enum N { \
        _1 = (1 << 1), \
};
#define BITFLAG_3(N,_1,_2,_3) \
enum N { \
        _1 = (1 << 1), \
        _2 = (1 << 2), \
};
/* etc. */
    
#define BITFLAG_N(_10,_9,_8,_7,_6,_5,_4,_3,_2,_1,_0,N,...)  BITFLAG_##N
#define BITFLAG(...)  BITFLAG_N(__VA_ARGS__,10,9,8,7,6,5,4,3,2,1)(__VA_ARGS__)

BITFLAG(
    X,
    FLAG1,
    FLAG2,
)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文