典型的C风格方法:
#define LOG_ERRORS 1 // 2^0, bit 0
#define LOG_WARNINGS 2 // 2^1, bit 1
#define LOG_NOTICES 4 // 2^2, bit 2
#define LOG_INCOMING 8 // 2^3, bit 3
#define LOG_OUTGOING 16 // 2^4, bit 4
#define LOG_LOOPBACK 32 // and so on...
// Only 6 flags/bits used, so a char is fine
unsigned char flags;
// initialising the flags
flags = LOG_ERRORS;
//initialising to multiple values with OR (|)
flags = LOG_ERRORS | LOG_WARNINGS | LOG_INCOMING;
// sets to 1 + 2 + 8 i.e. bits 0, 1 and 3
// testing for a flag
// AND with the bitmask before testing with ==
if ((flags & LOG_WARNINGS) == LOG_WARNINGS)
...
// testing for multiple flags
// as above, OR the bitmasks
if ((flags & (LOG_INCOMING | LOG_OUTGOING))
== (LOG_INCOMING | LOG_OUTGOING))
...
在C ++ 11中是否有更好的方法,它保留了旧的C风格界面(LOG_INCOMING | LOG_OUTGOING
)?即如何摆脱“丑陋”的方式来检查哪些位被设置?
我一直在关注std::bitset
,但后者仅测试位置查询(例如,它可以测试是否设置了第3位)并且无法测试类似的内容:
LOG_INCOMING | LOG_OUTGOING
答案 0 :(得分:4)
我会将您的宏替换为static const int
s(嗯,或者使用显式值的enum
),但除此之外您的实现就可以了。
你不应该仅仅因为可以用一些新的模板怪物替换好的,可靠的,健壮的,清晰的,自我记录的,简洁的,可靠的代码。
您的代码足够现代,这种模式仍在使用中。
答案 1 :(得分:3)
我认为0x / 1y功能的代码性能没有任何问题。如果它已经过充分测试,您可能希望避免重写(特别是如果现有代码依赖于它)。
如果只想了解如何使用功能的一些想法,可以采取一些不同的方法。
... constexpr
constexpr uint8_t bit(const uint8_t n) {
return 1 << n;
}
constexpr static const uint8_t LOG_ERRORS = bit(0);
constexpr static const uint8_t LOG_WARNINGS = bit(1);
if (flags & (LOG_ERROR | LOG_WARNINGS))
二进制文字......
static const uint8_t LOG_ERRORS = 0b00000001;
static const uint8_t LOG_WARNINGS = 0b00000010;
if (flags & (LOG_ERRORS | LOG_WARNINGS))
可变参数模板......
template<typename T, typename... Ts>
T bit_or(T t, Ts... ts) {
return t | bit_or(ts...);
}
template<typename T>
T bit_or(T t) {
return t;
}
template<typename T, typename... Ts>
bool any_set(T t, Ts... ts) {
return static_cast<bool>(t & (bit_or(ts...)));
}
constexpr uint8_t bit(const uint8_t n) {
return 1 << n;
}
constexpr static const uint8_t LOG_ERRORS = bit(0);
constexpr static const uint8_t LOG_WARNINGS = bit(1);
if (any_set(flags, LOG_ERRORS, LOG_WARNINGS))
我个人的偏好是避免std::bitset
,因为它不能在布尔上下文中直接评估。但是,我可能会考虑在类中包装flags
,并使用enum class : uint8_t
作为类型安全的标志。该类可能类似于Java的EnumSet
。您可以轻松地重置按位操作(&
,|
,^
,~
等等...),以保留C接口。
答案 2 :(得分:1)