0

Let's say we have a enum declared outside the main function in a C code.

We can access the members of the enum inside the function without issue, and also assign it to variables of int data type.

But, there exists the concept instantation of enum type, i.e.,

Why is it required when using enum elements with int also does the task?

I declared this outside the main function:

enum months {Jan, Feb, Mar};

..and accessed it's member(s) using int inside the main() function

int main () {
         int m=Feb;
         printf("%d", m);
}

(prints 1 on screen)

But it's popular to create an instance of the enum type in the function where it's used:

int main () {
         enum months m=Feb;
         printf("%d", m);
}

(prints 1 on screen)

Why is this needed when you can use int itself?

  • useful: https://stackoverflow.com/questions/22646165/what-is-the-use-of-enums-in-c-and-c – yano Jun 22 '23 at 04:40

3 Answers3

2

C has rather weak type safety overall, especially when it comes to enums as explained here: How to create type safe enums? As shown in that link, enums are essentially just glorified integers, especially enumeration constants, jan feb etc which are actually guaranteed to be of type int.

but we can use typedef enum to achieve slightly better type safety. Namely when passing enums as pointers, because C has much stronger type safety for pointers than for plain integer types.

Example:

typedef enum {Jan=1, Feb, Mar} months;

void print_month (const months* m)
{
  printf("%d\n", *m);
}

int main () {
    months m=Feb;
    print_month(&m); // ok

    int n=Feb;
    print_month(&n); // compiler error
}

(Make sure to compile as strict C with max warnings: What compiler options are recommended for beginners learning C?)

Lundin
  • 195,001
  • 40
  • 254
  • 396
0

If you use int, then it's simply not enum type, it's like using float for int, you can use but it's less specific and loses information.

int main () {
         int m=Feb;
         printf("%d", m);
}

Here, type of m is int. In first line of main function, there is implicit casting involved from enum months to int. Wherever you will use m it will work as int.

int main () {
         enum months m=Feb;
         printf("%d", m);
}

While in second case, type is enum months. Casting happens when you call printf.

Hope this helps.

Jiraiya
  • 52
  • 7
  • `enum months` may or may not be compatible with `int` however. There is no casting here, implicit _conversion_ might happen when you call `printf`. This is because `printf` is a variadic function and therefore comes with something called "default argument promotion". `printf` has no intelligence regarding enums at all, they are simply treated as any integer type. And in case an enumerated type happens to correspond to a small integer type, it gets implicitly converted to `int` during "default argument promotion". – Lundin Jun 22 '23 at 07:59
0

Instantiation is the creation of an actual variable (an instance) of a particular type. In the example, you choose to either create a local instance of the enumerated type, months, or an instance of an int type, which knows nothing about the names of months, but can still hold the underlying number that enum month variables use to represent months.

While it's true that enums are compiled to ints at runtime, enums add a layer of abstraction to our source-code that makes it easier for humans to understand. We use enum types when dealing with a limited set of valid values, each representing a different meaning. Using them is all about being nice to your future self, because C gives you free rein to do all sorts of things that might hurt later; Ben Klemens (see Resources) describes C as "Punk Rock"!

Humans read source code more frequently than the compiler does, especially when you work in a team. Using enum types makes the code clearer, so that you and your colleagues can understand the intent of the code. The compiler doesn't know about what your code is intended to do - it just does as it's told - but it really matters to you, the developer.

When you make use of the type system, you're making it easier for developers to understand and maintain the code. Even solo developers benefit from this, because you soon forget the details of your implementation. You're doing a favor to the future-you, by giving yourself a clue, just like when you choose meaningful names for your variables and functions. Also, enums tell the compiler which limited set of values are okay for variables of that type, thus giving it a chance to catch mistyped values at compile time, rather than failing at runtime.

Caveats

With C, you still need to explicitly check for invalid values, eg. in a switch statement with a default clause, especially if you do any arithmetic on the enum.

Ben Klemens is not entirely uncritical of how C handles enum types, especially for cluttering the compiler's global namespace, thereby requiring longer, clunkier identifiers to avoid name clashes in larger programs.

Resources

S. McConnell, Code complete: a practical handbook of software construction. Redmond, Wash: Microsoft Press, 1993.

B. Klemens, 21st century C, Second edition. Beijing ; Sebastopol, CA: O’Reilly Media, Inc, 2014.

Search terms C "code quality" or C "best practice".

Also, definitely check out Coding Standards for pure C (not C++) on this site.

Marco Pagliaricci
  • 1,366
  • 17
  • 31
  • 1
    "While it's true that enums are compiled to ints at runtime" Not really true. _Enumerated types_, what you call "instances" (there's no such formal term in C) are of an implementation-defined type picked by the compiler depending on system and enumeration constant range needed. _Enumeration constants_ (the stuff inside `enum { ... }`) are however guaranteed to be of type `int`. – Lundin Jun 22 '23 at 07:55