C Language

To share this page click on the buttons below;

Enumeration

Enumeration is a very simple concept and it deals with readability. Very often in the code you need to model something that is not a number nor a string, rather a quality or a part of something or a status. Enumeration is handy in this cases because it allows to associate a name with what you are trying to model.

Suppose that your application must deal with some colors: green, yellow or red (perhaps you are writing the code that drives a traffic light). The simple solution is to use an integer variable and associate a meaning to some value. For example you can say that the color green is associated with the value 1, the color yellow with the value 2 and the color red with the value 3. That is a perfectly valid choice, but if you use numbers you have to remember the association and within your code it will not be immediately understandable what color are you using.

Enumeration come in situation like that and automatically associate some numbers with user defined names, those names become a sort of new range of values for a new sort of type: an enumerative type.

Defining an enumerative type

To define an enumeration you use the reserved word enum followed by a tag which is just the name of the enumeration, followed by a pair of braces: within these braces you put the list of the symbolic values you want your enumerative variables may assume. For example, in the case of our traffic light colors:

enum tf_colors {
  TF_GREEN,
  TF_YELLOW,
  TF_RED
};

An enumeration though is anything else than an integer variable, the enum thing just associate a symbolic name to that integer to improve the readability of the code.

By default (if you do not specify anything else) the integer values associated with the symbolic name start start from 0 (zero) and they are simply incremented by 1 for each new symbolic name. So, for our example, 0 is associated with the symbolic name TF_GREEN, 1 is associated with the symbolic name TF_YELLOW and 2 is associated with TF_RED.

You can associate your own values, the first and more straightforward way is simply to specify the value of the first symbolic name like this:

enum tf_colors {
  TF_GREEN = 5,
  TF_YELLOW,
  TF_RED
};

So, now TF_GREEN is 5 and the other values are obtained with an increment of 1 (so TF_YELLOW is 6 and TF_RED is 7).

Although is much more less common you can specify your own value for each symbolic name like this (but I cannot imagine any sensible reason to do that, even worst if you want to fix the enumaration to some values you are probably missing the very purpose of symbolic name associated to the enumeration):

enum tf_colors {
  TF_GREEN = 5,
  TF_YELLOW = 78,
  TF_RED = 10
};

Name clashing

Someone might have been noticed that I used the prefix TF_ for the symbolic name, so instead of simply define the symbolic name GREEN I used TF_GREEN. Why so?

Well, first of all I used a prefix that remind me the enumerative that symbolic names belong, but this is not the only reason: in big projects you will face the problem of name clashing. What does it mean? It means that the name of the variables or the symbolic name of the enumeration have to be unique within the whole project (that is a simplification, but let stay simple for the moment). Using common symbolic name like GREEN or RED expose us to the risk that other programmers might have already used the same symbolic name, using a prefix reduce this kind of risk.

A complete example

#include <stdio.h>
#include <unistd.h>

/* program to demonstrate enumeration */

enum tl_colors {
    TF_GREEN,
    TF_YELLOW,
    TF_RED
};

void main(void) {

    printf("PROGRAM to demonstrate enumeration\n");

    enum tl_colors traffic_light = TF_RED;

    int i = 0;

    for(i = 0; i < 10; i++) {

        switch(traffic_light) {
            case TF_RED:
                traffic_light = TF_GREEN;
                printf("!  RED (Stop) \n");
                sleep(1);
            break;

            case TF_GREEN:
                traffic_light = TF_YELLOW;
                printf("-> GREEN (Go)\n");
                sleep(1);
            break;

            case TF_YELLOW:
                traffic_light = TF_RED;
                printf("*  YELLOW (Better to stop)\n");
                sleep(1);
            break;

            default:
                traffic_light = TF_RED; 
                printf("!  RED (Stop)\n");
            break;
        }
    }
}

The program simulates the behavior of a traffic light, please note the use of the function sleep (defined in unistd.h) which allow you to pause the program for a number of seconds equal to its argument. Sleep function is much more common in multi-threading programming but here it seemed a good simple place to use it. The for loop and the switch case all together implement what is called a state machine (and this is a very simple example of state machine). A state machine is a kind of algorithm which has several states, in each state (which is implemented using a particular case in the switch) the application does something different and for each state one or more conditions are evaluated in order to decide which has to be the next state. State machine are a very common algorithm because almost every electronic device or application have different state of use and for each state some operations are allowed and some not. For example an electronic device can be POWERED, ON, OFF, WAITING FOR COMMAND, LOW POWER CONSUMPTION and so on. Of course this is just a very small introduction to state machines.

To share this page click on the buttons below;