gpt4 book ai didi

c - 如何在 C 中定义枚举标志,而不显式设置每个成员值?

转载 作者:行者123 更新时间:2023-11-30 19:56:25 25 4
gpt4 key购买 nike

在 C 语言中,常见的做法是...

enum {
A,
B,
C,
};

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

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

是否可以定义标志而不必显式列出每个值?

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

<小时/>

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

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

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

这样做的好处是添加/删除位,不需要更改 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,并依赖于定义一些唯一的起始值来使用枚举...这会污染 namespace 。

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

最佳答案

如果您愿意超越纯 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.c foo.c.in 通过在其上运行过滤器。

请注意,过滤器不能处理一行上 @...@ 的多次使用,并且如果标志数量超过 Perl 位数,过滤器将无法正常运行认为是整数。它还扩展了注释(应该不是问题)和字符串文字(可能是问题)中的 @FLAG@ 。铃声、口哨和错误检查留作练习。

关于c - 如何在 C 中定义枚举标志,而不显式设置每个成员值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28509144/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com