Enumerated (enum) Data Types in C

The Enumerated data type allows the programmer to invent the programmer's own data type and decide what value the variables of this data type may carry. Enum or enumerator is an integer or number with defined meaningful names. Enum is often used inside C programs to replace a hard-coded number with some meaningful symbols.

No Enumerated data type program

Let's see one example situation. Here we are dealing with the state of a task. This program deals with hard-coded numbers and it is decoding the state as a printable output.

/* A function prints state of a task with numbers */
void print_task_state (int state)
{
  switch (state) {
    csase 0:
      printf ("Task has been added.\n");
      break;
    case 1:
      printf("Task is ready.\n");
      break;
    case 2:
      printf("Task is running.\n");
      break;
    case 3:
      printf("Task is waiting.\n");
      break;
    case 4:
      printf("Task has been terminated.\n");
      break;
  default:
      printf("Task in undefined state.\n");
  }
}

This program may work well but it is not comprehensive to the readers. A nice way to make it more readable is through enumerators.

Enumerated data type in C program

This example has task state in hard coded numbers. It is difficult to remember these numbers. Enum can be used here. Let's re-write this same program with one enum type which will takecare this task state.

/* A function prints state of a task with enum */
enum state_t {
  TASK_ADDED,
  TASK_READY,
  TASK_RUNNING,
  TASK_WAITING,
  TASK_TERMINATED
};

void print_task_state (enum state_t state)
{
  switch (state) {
    csase TASK_ADDED:
      printf ("Task has been added.\n");
      break;
    case TASK_READY:
      printf("Task is ready.\n");
      break;
    case TASK_RUNNING:
      printf("Task is running.\n");
      break;
    case TASK_TERMINATED:
      printf("Task has been terminated.\n");
      break;
  default:
      printf("Task in undefined state.\n");
  }
}

Enumerated data type vs Macros

Integer values as Macros can be an alternative to Enumerated data type. However these macros are not data types. They are still replaced to numbers during pre-processing.

#define TASK_ADDED      0
#define TASK_READY      1
#define TASK_RUNNING    2
#define TASK_WAITING    3
#define TASK_TERMINATED 4

Advantages of Enumerated Data Type:

From the above example this is clear that enum makes this example more readable and more manageable. Here are the key benefits -

  1. Makes program more readable to the fellow developers.
  2. Makes program more manageable while dealing enum type of variables.
  3. Using enumerators reduces programming error.

Enumerator syntax

They keyword "enum" is used to define an enum type. enum type should contain Enumerator names separated by commas ",". They are enclosed by a curly brackets {}.


enum <enum name> {
  <Enumerator name> [Optional = <number value>],
  ...
};

enum state_t {
  TASK_ADDED,
  TASK_READY,
  TASK_RUNNING,
  TASK_WAITING,
  TASK_TERMINATED
}

Enumerator initialization

First enumerator name takes a default value of zero (0). Starting from zero each next enumerator should have a value incremented by one from its previous enumerator entry. Thus the calculation is current enum value = (previous enumerator value + 1).

enum state_t {
  TASK_ADDED,
  TASK_READY,
  TASK_RUNNING,
  TASK_WAITING,
  TASK_TERMINATED
}

/* Same as */
enum state_t {
  TASK_ADDED = 0,
  TASK_READY,
  TASK_RUNNING,
  TASK_WAITING,
  TASK_TERMINATED
}

/* Same as */
enum state_t {
  TASK_ADDED = 0,
  TASK_READY = 1,
  TASK_RUNNING = 2,
  TASK_WAITING = 3,
  TASK_TERMINATED = 4,
}

The value of Enumerator name can be assigned by assignment operator ("="). It takes +1 of previous value to define next value unless we define explicitly.

enum state_t {
  TASK_ADDED = 0,
  TASK_READY = 2,
  TASK_RUNNING,
  TASK_WAITING,
  TASK_TERMINATED
}

/* Same as */
enum state_t {
  TASK_ADDED = 0,
  TASK_READY = 2,
  TASK_RUNNING = 3,
  TASK_WAITING = 4,
  TASK_TERMINATED = 5,
}

Enumerator Example

Here is a program to store the sport which a person has played. An enumerated data type sports is needed which stores the four possible values: cricket, football, hockey and tennis.

The format of the enum declaration is similar to that of a structure.

/* Declaration */
enum sports
{
  cricket, football, hockey, tennis
};

/* Define two enums */
enum sports n1, n2;

/* Assign enum values */
n1 = cricket;
n2 = football;

This declaration has two parts:

  • First part: declares data type and specifies possible values
  • Second part: defines variables of this data type
  • Third part: Values given to the variable has to be among the values given in the original declaration.

The internal permissible values of the enumerated data types correspond to integers starting with zero. In the above example, cricket corresponds to 0, football as 1, hockey as 2 and tennis as 3.

The method of assigning numbers by the compiler may be overridden by the programmer as shown below.

enum sports
{
  cricket = 10, football = 20, hockey = 30, tennis = 40
};

Compiler will use cricket as 10, football as 20, hockey as 30 and tennis as 40

Enumerator complete example

The main use of the enumerated data type is to make the listings in a program easier to read. Values like cricket, football are easier to read in a program than integers like 0, 1.

The following program explains the benefits of enums:


enum sports
{
  cricket, football, hockey, tennis
};

struct player
{
  char name[50];
  int age;
  enum sports sport_played;
};

int main (int argc, char *argv[])
{
  struct sports_man s;

  strcpy(s.name,"Sachin");
  s.age = 34;
  s.sport_played = cricket;

  printf("\nName : %s",s.name);
  printf("\nAge : %d",s.age);
  printf("\nSports Played : %d",s.sport_played);

}
Output Given:
Name : Sachin
Age : 34
Sport Played : 0

Deconstructing the program reveals that a data type enum sports has been defined with four values cricket, football, hockey and tennis. A variable sport_played has been defined in a structure player with two other elements.

Value is assigned to the variables in the structure. s.sport_played is assigned value cricket which is much more informitive than 0.

Although the value of s.sport_played is assigned value cricket, it actually receives the value 0 and this is the value shown when the variable is used in the program.

Functions like printf() and scanf() cannot use the enumerated values directly. It can only use the integer values.

Enum and string mapping

Enumerators are integer types and they hold some values based on the enum type definitions. They are not suitable for user interactions and they cannot directly be used in user interfaces.

So the only way a user can understand an enum value if that is converted to a string and given to the user interface. An enum can be translated to a string which can be shown in user interfaces. Same way string can be converted to enum to be used in the C program.

We have defined a structure to hold the numeric value of the enum and its corresponding string representation. This is generally known as a map entry data structure.

struct enum_string_pair
{
  int enum_val;
  char * enum_string;
};

We are creating a map table with all the defined numeric values of the enum definitions.

struct enum_string_pair enum_string_pairs[4] ={
  {cricket,  "cricket"},
  {football, "football"},
  {hockey,   "hockey"},
  {tennis,   "tennis"}
};

We will further define utility functions to do the translations.

Convert Enum to String

This function can be used to translate a numeric value of enum to a human-readable string. We are iterating our enum to string map table and checking the value of enum to each entry. Enum value should match one of the defined values in the map table. Once matched we take the string value from the map table and return the same. By default, the default return value is set to "undefined". This will be returned when there is no match found.

char *enum_to_string(struct enum_string_pair *pairs, int count, int enum_val)
{
  int i;
  char * ret_str="undefined";
  
  for (= 0; i < count; i++)
  {
    if(pairs[i].enum_val == enum_val)
      ret_str = pairs[i].enum_string;
  }
  return ret_str;
}

Convert String to Enum

This function can be used to translate a string to a numerical value of enum. We are iterating our same enum to string map table and checking the string to each entry. This string should match one of the defined strings in the map table. Once matched we take the numerical value of the enum from the map table and return the same. By default, the default return value is set to -1. This will be returned when there is no match found.

int string_to_enum(struct enum_string_pair *pairs, int count, char* string)
{
  int i;
  int ret_val = -1;
  
  for (= 0; i < count; i++)
    if(strcmp(pairs[i].enum_string, string) == 0)
      ret_val = pairs[i].enum_val;
          
  return ret_val;
}

Convert String to Enum and Enum to String program

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

enum sports
{
  cricket=10, football=20, hockey=30, tennis = 40
};

struct enum_string_pair
{
  int enum_val;
  char * enum_string;
};

struct enum_string_pair enum_string_pairs[4] = {
  {cricket,  "cricket"},
  {football, "football"},
  {hockey,   "hockey"},
  {tennis,   "tennis"}
};
    
char *enum_to_string(struct enum_string_pair *pairs, int count, int enum_val)
{
  int i;
  char * ret_str = "undefined";
  
  for (= 0; i < count; i++)
  {
    if(pairs[i].enum_val == enum_val)
      ret_str = pairs[i].enum_string;
  }
  return ret_str;
}
    
int string_to_enum(struct enum_string_pair *pairs, int count, char* string)
{
  int i;
  int ret_val = -1;
  
  for (= 0; i < count; i++)
    if(strcmp(pairs[i].enum_string, string) == 0)
      ret_val = pairs[i].enum_val;
          
  return ret_val;
}
    
int main (int argc, char *argv[])
{
  enum sports s;
  int i, count;
  char string[20] = {0};
  
  count = sizeof(enum_string_pairs)/sizeof(enum_string_pairs[0]);
  printf("Enum to string convertions ");
  for (= 0; i < count; i++)
  {
    printf("Enum sports #%d numeric value %d to string %s\n",
           i,
           enum_string_pairs[i].enum_val,
           enum_to_string(enum_string_pairs,
           count,
           enum_string_pairs[i].enum_val));
  }
  printf("String to Enum convertions\n");
  while(1)
  {
    printf("Enum sports enter a value: ");
    gets(string);
    
    if(strcmp(string, "exit") == 0)
      break;

    printf("Enum sports string %s to numeric value %d\n",
           string,
           string_to_enum(enum_string_pairs, count, string)
           );
  }
  return 0;
}

Convert String to Enum and Enum to String program

Enum to string convertions
Enum sports #0 numeric value 10 to string cricket
Enum sports #1 numeric value 20 to string football
Enum sports #2 numeric value 30 to string hockey
Enum sports #3 numeric value 40 to string tennis
String to Enum convertions
Enum sports enter a value: football 
Enum sports string football to numeric value 20
Enum sports enter a value: cricket
Enum sports string cricket to numeric value 10
Enum sports enter a value: xyz
Enum sports string xyz to numeric value -1
Enum sports enter a value: exit

About our authors: Team EQA

You have viewed 1 page out of 252. Your C learning is 0.00% complete. Login to check your learning progress.

#