Enum vs Macro States C ++

时间:2010-07-13 19:27:53

标签: c++ macros enums

(问题与我以前的问题herehereherehere有关。

我正在维护一个非常古老的应用程序,该应用程序几年前从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 = 0x00000001BIT1 = 0x00000002

SystemStatus systemStatus;

systemStatus = SYSTEM_ONLINE

在您看来,使用setBit和clrBit宏更像C或C ++之类的 - 并且最好简单地将变量声明为枚举类型并摆脱所有旧的setBit / clrBit东西吗?

6 个答案:

答案 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)

如果可以确保一次只能设置不超过一位,那么只使用enum。否则,您必须为所有位组合设置枚举常量,这很快就会很快变得复杂。您可以使用一组#define语句(或者我认为是enum)来使用友好名称对位掩码进行别名,但您仍然可能最终使用set / clear宏。 < / p>

设置和清除位似乎更像是一种“类C”方法。但是,我(个人)并不认为你的enum方法非常“C ++ - 就像”。对于更类似C ++的方法,创建一个类来表示系统状态并操纵类成员而不是位字段。您甚至可以重载+-运算符,使其分别与setBitclrBit函数相似。例如,当且仅当设置时,使用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();
}

使用此样式封装了有关如何实现信息存储的实现。