19

在 C++03 中,可以通过将强类型枚举放入类(或命名空间)中来模拟强类型枚举:

struct MyEnum
{
  enum enumName
  {
    VALUE_1 = 1,
    VALUE_2,
  };
};

并使用它:

MyEnum::enumName v = MyEnum::VALUE_1;

是否可以在 C 中做类似的事情?如果是,如何?


我试过这样,但当然这不起作用:

struct A
{
  enum aa
  {
    V1 = 5
  };
};

int main()
{
  A::aa a1 = A::V1;
  enum A::aa a2 = A::V1;
  struct A::aa a3 = A::V1;

  return 0;
}
4

3 回答 3

6

这是我的解决方案。与@Eric 的设计相比有一些优势:

  • 支持相等测试(例如A_VALUE_0 == value
  • 不依赖 C99 的复合文字
  • 可以强制转换为枚举分配不正确的值。

缺点:

  • 标志不起作用(例如A_VALUE_0 | A_VALUE_1
  • 不能被switch'd
  • 在测试相等性时可能会使 IDE 混淆错误行的位置(例如A_VALUE_0 == B_VALUE_1

笔记:

  • 永远不要取消引用这种类型的指针。会比兰博基尼更快地导致崩溃

这是实现(用-Werror&编译-pedantic):

typedef struct A { char empty[1]; } *A; // we use 'empty' so that we don't get a warning that empty structs are a GNU extension
#define A_VALUE_0 ((A) 0x1)
#define A_VALUE_1 ((A) 0x2)
#define A_VALUE_2 ((A) 0x4)

typedef struct B { char empty[1]; } *B;

#define B_VALUE_0 ((B) 0x0)
#define B_VALUE_1 ((B) 0x1)
#define B_VALUE_2 ((B) 0x2)

int main()
{
    A a = A_VALUE_0;

    int equal = (a == A_VALUE_1); // works!
    int euqal = (a == B_VALUE_1) // doesn't work

    A flags = A_VALUE_0 | A_VALUE_1; // doesn't work!

    switch (a) { // doesn't work
        case A_VALUE_0:
            puts("value 0");
            break;
        case A_VALUE_1:
            puts("value 1");
            break;
        case A_VALUE_2:
            puts("value 2");
            break;
        default:
            puts("unknown value");
            break;
    } // doesn't work

    // casting works for assignment:
    A b = (A) (B_VALUE_2);

    return 0;
}
于 2012-08-10T15:24:55.410 回答
3

你可以这样做:

// Declare A to use for an enumeration, and declare some values for it.
typedef struct { int i; } A;
#define A0  ((A) { 0 })
#define A1  ((A) { 1 })

// Declare B to use for an enumeration, and declare some values for it.
typedef struct { int i; } B;
#define B0  ((B) { 0 })
#define B1  ((B) { 1 })


void foo(void)
{
    // Initialize A.
    A a = A0;

    // Assign to A.
    a = A1;

    // Assign a value from B to A.
    a = B0; // Gets an error.
}

这会给您一些输入,但这可能会很麻烦,具体取决于您要对枚举及其值执行的其他操作。

于 2012-08-10T14:49:12.893 回答
3

由于 C 不提供命名空间,因此您可以使用前缀。

enum MyEnum {
    MyEnumA = 1,
    MyEnumB,
    MyEnumC
};

enum OtherEnum {
    OtherEnumA = 1,
    OtherEnumB
};

然后,为了简化变量声明,您可以为枚举声明类型,如下所示:

typedef enum MyEnum MyEnum;
typedef enum OtherEnum OtherEnum;

最后,如果您不想允许隐式转换OtherEnumB类型MyEnum,Clang 提供了-Wenum-conversion标志(不幸的是,我认为 GCC 中没有类似的标志)。

/tmp/test.c:24:20: warning: implicit conversion from enumeration type 'enum OtherEnum' to different enumeration type 'MyEnum' (aka 'enum MyEnum') [-Wenum-conversion]
    MyEnum value = OtherEnumB;
           ~~~~~   ^~~~~~~~~~
1 warning generated.

这样做的好处是简单、易于理解,并且可以很好地与您的(至少我的)IDE 的自动完成功能配合使用。

于 2012-08-10T15:54:52.077 回答