如何在C中模拟强类型枚举?

时间:2012-08-10 14:19:57

标签: c enums

在C ++ 03中,可以通过将它放在类(或命名空间)中来模拟strongly typed enum

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;
}

3 个答案:

答案 0 :(得分:5)

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

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

缺点:

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

注意:

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

以下是实施(使用-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;
}

答案 1 :(得分: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.
}

这会给你一些打字,但这可能会令人讨厌,这取决于你想用枚举及其值执行的其他操作。

答案 2 :(得分:2)

由于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的自动完成功能配合良好。

相关问题