0

I have an enum day_t which contains the days of the week.

typedef enum
{
    monday = 1,
    tuesday,
    wednesday,
    thursday,
    friday,
    saturday,
    sunday
} day_t;

I'd like to restrict the argument of a function setDay(someType Day) with the enum definitions (friendly names) only. Is it possible using an enum or something else?

For example I'd like to type in code the argument like this, with intellisense allowing me to see the other friendly names:

setDay(day.wednesday);

Thanks.

PLB
  • 197
  • 1
  • 10
  • 2
    That's not a feature of C. For the code-writing autocomplete question, you could fake it with a struct where the elements have the same names as their enum values, but that's not a good solution. You may want to consider C++ and it's `enum class` if this is important. As for restricting the argument values, that's just something you have to check in the function itself. – Thomas Jager Aug 26 '21 at 12:39
  • 2
    The C standard does not provide features for this. Partly for historical reasons of how C developed, `enum` types are largely integer types and may be used interchangeably with other integer types. Separation between them is weak. Specific compilers might provide some additional features to warn you in a few cases. – Eric Postpischil Aug 26 '21 at 12:40
  • `day.wednesday` isn't valid C so you can't do that. You might have to use a struct wrapper etc to get code completion in some IDE. – Lundin Aug 26 '21 at 13:20

1 Answers1

2

It's possible to do this by using the tricks from How to create type safe enums? Taking the trick of type safe assignment described in the accepted answer:

typedef union
{
  day_t monday;
  day_t tuesday;
  day_t wednesday;
  day_t thursday;
  day_t friday;
  day_t saturday;
  day_t sunday;
} typesafe_day_t;

#define day_assign(var, val) _Generic((var), day_t: (var) = (typesafe_day_t){ .val = val }.val)

Then given some function void set_day (day_t day), we can design a safe version using a wrapper macro:

#define set_day_s(day) set_day( day_assign((day_t){0},day) )

This makes a temporary copy of the passed argument and runs that through the type safety macro, blocking everything that isn't one of the mentioned enum constants.

Full example:

typedef enum
{
  monday = 1,
  tuesday,
  wednesday,
  thursday,
  friday,
  saturday,
  sunday
} day_t;

typedef union
{
  day_t monday;
  day_t tuesday;
  day_t wednesday;
  day_t thursday;
  day_t friday;
  day_t saturday;
  day_t sunday;
} typesafe_day_t;

#define day_assign(var, val) _Generic((var), day_t: (var) = (typesafe_day_t){ .val = val }.val)

void set_day (day_t day){ /* ... */ }
#define set_day_s(day) set_day( day_assign((day_t){0},day) )

int main (void)
{
  set_day_s(monday); //  OK

  day_t d=monday;
//  set_day_s(d);      // compiler error
//  set_day_s(1);      // compiler error
}
Lundin
  • 195,001
  • 40
  • 254
  • 396