【问题标题】:Using C flag enums in C++在 C++ 中使用 C 标志枚举
【发布时间】:2012-04-26 18:15:15
【问题描述】:

我有一个像这样定义枚举的 C API:

typedef enum
{
  C_ENUM_VALUE_NONE    = 0,
  C_ENUM_VALUE_APPLE   = (1 << 0),
  C_ENUM_VALUE_BANANA  = (1 << 1),
  C_ENUM_VALUE_COCONUT = (1 << 2),
  // etc.
  C_ENUM_VALUE_ANY     = ~0
} CEnumType;

有一个使用枚举的方法,定义为:

void do_something(CEnumType types);

在 C 中,你可以这样调用:

do_something(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA);

但是,如果您尝试在 C++(Linux、g++ 编译器)中以这种方式调用它,则会收到错误,从“int”到“CEnumType”的转换无效

在我的 C++ 应用程序中使用此 C API 的正确方法是什么?

【问题讨论】:

    标签: c++ c enums


    【解决方案1】:

    您需要将 ints 转换为 C++ 中的枚举,但您可以将转换隐藏在自定义 OR 运算符中:

    CEnumType operator|(CEnumType lhs, CEnumType rhs) {
        return (CEnumType) ((int)lhs| (int)rhs);
    }
    

    有了这个操作符,你就可以写出你的原作了

    do_something(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA);
    

    它会毫无问题地编译和运行。

    【讨论】:

    • 拥有一个枚举类型的对象,其值不是指定的枚举值之一,它甚至是明确定义的行为?
    • 我很确定整个 (int) 转换是多余的,因为您的枚举已经有一些存储类型,或者可以使用枚举 X 指定:int {}
    【解决方案2】:

    C++ 对枚举有比 C 更严格的规则。调用时需要将值转换为枚举类型:

    do_something((CEnumType)(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA));
    

    或者,如果您想避免每次调用时都编写强制转换,您可以编写一个封装函数,该函数采用 int 为您执行强制转换:

    void do_something_wrapper(int types)
    {
        do_something((CEnumType)types);
    }
    ...
    do_something_wrapper(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA);
    

    虽然我不知道我是否想看看当你将苹果与香蕉交叉时会得到什么......

    【讨论】:

      【解决方案3】:

      在按位运算的情况下,表达式计算为原始类型,即intlong 等。但是,您的函数采用非原始类型 (CEnumType)。我知道绕过这个的唯一方法是强制转换表达式。例如:

      do_something((CEnumType) (C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA));
      

      【讨论】:

      • +1 用于将表达式评估记录到int。 do_something(C_ENUM_VALUE_APPLE) 无需任何强制转换即可正常工作。这是因为表达式评估为 int 需要强制转换
      【解决方案4】:

      CEnumType A;

      A = (CEnumType)(A | C_ENUM_VALUE_APPLE);

      你也可以这样用。

      【讨论】:

        【解决方案5】:

        通过 or-ing 两个枚举值,您正在创建一个无效值(0x3 不在枚举 CEnumType 中)。枚举不是位域。如果你想要一个位域,定义一个。

        如果你想强制它通过,你可以强制转换值,但这可能会让一些只指望能够获取枚举值的代码感到惊讶。

        do_something((CEnumType)(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA));
        

        【讨论】:

        • 他没有定义这个接口,他使用的是其他人为 C 设计的接口。他大概不能(也不应该)更改库代码。
        • 枚举是为了声明的简单性,函数接受枚举只是为了提示 C 开发人员在哪里寻找可以异或形成输入的值......这没有错,只是不同思维方式。更像 C 而不是 C++。
        • "通过 or-ing 两个枚举值,您正在创建一个无效值(0x3 不在枚举 CEnumType 中)" 我认为这是错误的。这只是因为按位运算符计算为 int 并因此产生错误。不是因为它评估为不在枚举中的 0x3
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-17
        • 2018-01-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多