(问题与我以前的问题here,here,here和here有关。
我正在维护一个非常古老的应用程序,该应用程序几年前从DOS移植到Windows,但许多旧的C约定仍然继续发展。
一个特定的约定是setBit和clrBit宏:
#ifndef setBit
#define setBit(word, mask) word |= mask
#endif
#ifndef clrBit
#define clrBit(word, mask) word &= ~mask
#endif
我发现我可以将变量声明为枚举类型,并将我的变量设置为等于定义的枚举值之一。
enum SystemStatus
{
SYSTEM_ONLINE = BIT0,
SYSTEM_STATUS2 = BIT1,
SYSTEM_STATUS3 = BIT2,
SYSTEM_STATUS4 = BIT3
};
使用BIT0 = 0x00000001
,BIT1 = 0x00000002
等
SystemStatus systemStatus;
systemStatus = SYSTEM_ONLINE
在您看来,使用setBit和clrBit宏更像C或C ++之类的 - 并且最好简单地将变量声明为枚举类型并摆脱所有旧的setBit / clrBit东西吗?
答案 0 :(得分:7)
否则不能 - 指定枚举值会覆盖整个值,而宏会更改现有值中的位。什么是BIT0,BIT1等?这就像定义INT0,INT1等 - 可怕的做法。
最重要的是,旧的C风格代码会给你带来什么问题吗?如果没有,请应用这个历史悠久的规则 - 如果没有破坏,请不要修复它。
答案 1 :(得分:6)
setBit& clrBit很好,虽然我会将它们转换为C ++中的内联函数。如果状态位彼此独立,它们将非常方便,例如:
SystemStatus systemStatus = SYSTEM_ONLINE | SYSTEM_STATUS3;
是有效的设置。
systemStatus = clrBit(systemStatus, SYSTEM_STATUS3);
systemStatus = setBit(systemStatus, SYSTEM_STATUS4);
答案 2 :(得分:4)
我认为你的目的令人困惑。枚举是关于设置要用作标志的值。 setBit和clrBit是关于数据操作的。这些数据可能恰好是一面旗帜,但这确实是两种观念之间唯一的关系。
话虽这么说,宏肯定不是C ++的做事方式。您将使用内联函数。例如:
template<typename T>
inline T& setBit(T& word, T mask) { return word |= mask; }
template<typename T>
inline T& clrBit(T& word, T mask) { return word &= ~mask; }
编辑以抵挡挑剔者:
这只是您如何实现这些功能的一个示例。您不需要使用模板,可以使用两个模板参数而不是1,如果需要,可以使用void函数或值而不是引用(尽管它会丢失一些原始语义)。重点是获得类型安全的好处,这在宏中是不会找到的(在宏的许多其他缺点中)。 http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.5
编辑:这是一个用于比较的无效,非模板版本
inline void setBit(unsigned int word, unsigned int mask) { word |= mask; }
inline void clrBit(unsigned int word, unsigned int mask) { word &= ~mask; }
答案 3 :(得分:2)
如果您确定在该代码的所有组合和排列中,人们一次只能使用一个位,它们在设置之前清除并且从不连续设置两次,那么请确保使用enum代替。它将更清晰,更易读。但是,如果有时系统是0101,那么你的枚举就无法处理。
好的,如果枚举是比特标志,那么你可以写
systemStatus = SYSTEM_ONLINE | BIT2;
然后我猜这是可读的并且可以支持组合,好的。
答案 4 :(得分:1)
如果可以确保一次只能设置不超过一位,那么只使用 < / p>
enum
。否则,您必须为所有位组合设置枚举常量,这很快就会很快变得复杂。您可以使用一组#define
语句(或者我认为是enum
)来使用友好名称对位掩码进行别名,但您仍然可能最终使用set / clear宏。
设置和清除位似乎更像是一种“类C”方法。但是,我(个人)并不认为你的enum
方法非常“C ++ - 就像”。对于更类似C ++的方法,创建一个类来表示系统状态并操纵类成员而不是位字段。您甚至可以重载+
和-
运算符,使其分别与setBit
和clrBit
函数相似。例如,当且仅当设置时,使用systemStatus -= SYSTEM_ONLINE
(带#define SYSTEM_ONLINE (1<<31)
或类似的)清除“系统在线”位。你甚至可以从STL Bitset继承并重用大部分功能。
修改:OP澄清BIT0
等是位掩码,因此我的第一段不再相关。
答案 5 :(得分:1)
我同意 bta 关于如果你想使用C ++方法,你应该创建一个抽象所有状态实现的类。
但我不会超载+ =, - =运算符因为你继续带着C老学校。
我建议声明方法来做到这一点。
你可以选择一个带布尔标志的方法或两个用于设置和放大的方法。明确。
class Status{...};
void main(){
Status status;
//first approach
status.SystemOnline(true);
status.BackUPOnline(false);
//second approach
status.SetEmergencySystem();
status.ClearSystemOnline();
}
使用此样式封装了有关如何实现信息存储的实现。