Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to emulate strongly typed enum in C?

Tags:

c

enums

In C++03, it is possible to emulate strongly typed enum by putting it in a class (or a namespace ) :

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

and to use it :

MyEnum::enumName v = MyEnum::VALUE_1;

Is it possible to do something similar in C? If yes, how?


I tried like this, but off course that doesn't work :

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;
}
like image 372
BЈовић Avatar asked Aug 10 '12 14:08

BЈовић


People also ask

Are enums strongly typed?

Enum Class C++11 has introduced enum classes (also called scoped enumerations), that makes enumerations both strongly typed and strongly scoped.

What is an enum in TypeScript?

In TypeScript, enums, or enumerated types, are data structures of constant length that hold a set of constant values. Each of these constant values is known as a member of the enum. Enums are useful when setting properties or values that can only be a certain number of possible values.


1 Answers

Here's my solution. Has a few advantages over @Eric's design:

  • Supports equality testing (e.g. A_VALUE_0 == value)
  • Doesn't rely on C99's compound literals
  • Can cast to assign an improper value to a enum.

Disadvantages:

  • Flags do not work (e.g. A_VALUE_0 | A_VALUE_1)
  • Cannot be switch'd
  • Can confuse the IDE on where the error lines are when testing for equality (e.g. A_VALUE_0 == B_VALUE_1)

Notes:

  • NEVER dereference a pointer of this type. Will cause crashes faster than a Lamborghini

Here's the implementation (compiled with -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;
}
like image 195
Richard J. Ross III Avatar answered Sep 22 '22 15:09

Richard J. Ross III