ENUMERATIONS

Enumerations

Article by:
Date Published:
Last Modified:

Overview

Enumerations in C are in their most basic sense, a way of creating a meaningful word-based list type.

Enumerations are an alternative to using C preprocessor macros to create words which represent numbers. For example:

1
2
3
4
#define RED     0
#define GREEN   1
#define BLUE    2
#define YELLOW  3

If you find yourself doing this, think carefully, would an enumeration be a better way? You can achieve the exact same result with:

1
2
3
4
5
6
7
typedef enum
{
    RED,
    GREEN,
    BLUE,
    YELLOW
} colours_t;

Usefullness

Enumerations are commonly used for:

  • Creating an list of something (e.g. COLOURS = RED, GREEN, BLUE, …)
  • Accessing hardware registers in embedded systems (used for creating meaningful register names).
  • Creating state variables (variables which describe a state in a state machine, commonly used with a switch statement)

Syntax

Enums can be defined it two separate ways. The non-typedef way:

1
2
3
4
5
6
7
8
enum myColoursType {
    RED,
    GREEN,
    BLUE,
    YELLOW
} colours_t;

enum colours_t myColoursType = BLUE;

Or the typedef way:

1
2
3
4
5
6
7
8
typedef enum {
    RED,
    GREEN,
    BLUE,
    YELLOW
} colours_t;

colours_t myColours = BLUE;

Notice when using the first method (non-typedef), everytime you create a variable of the enumeration type you have to write the word enum first. Using the second method (typedef), the enum keyword can be omitted.

By default, the compiler will make the first enumeration value equal to 0, the second equal to 1 and so on. However, you can specify the values you wish the enumerations to take on:

1
2
3
4
5
6
typedef enum {
    RED = 2,
    GREEN = 5,
    BLUE,
    YELLOW = 8
} colours_t;

If no value is specified, the compiler will increment by 1 as usual, so in the above case, BLUE = 6.

Interchangeability

In C, enum types and integer types are normally interchangeable. This can either be a good or bad thing, depending on your viewpoint. C++ allows for stricter type checking with the recently introduced enum class (strongly-typed enums), which cannot be compared with integer types. Strongly-typed enums also allows you to specify the width of the integer used to store the enumeration.

Optimisation

You are not allowed to take a reference (pointer) to an enumeration (they are not allowed to be lvalues), while you can with a const int. This means they can be optimised, while const int cannot.

The Data Type Of An Enum

The data type of an enumeration is implementation defined. This is what the standard has to say…

The choice of type is implementation-defined, but shall be capable of representing the values of all the members of the enumeration.

Normally you do not care what the width is, as long as it works! However, it certain cases, such as when you are packing an enumeration into a structure and want everything to be of a particular size, you want to exactly specify the enumeration width. You can force an enumeration to be of a larger data type than default by a simple trick of adding a very large number to the end of your enumeration.

1
2
3
4
5
6
typedef enum {
    FIRST_VAL,
    SECOND_VAL,
    // ...
    FORCE_ENUM_WIDTH = MAX_INT // This here forces the enumeration to be at least a particular width
} myEnum_t;

Some compilers support directives which will change the default size of an enumeration. For example, in GCC, you can add the compiler flag:

1
-fshort-enums

Which will make all enumerations use the smallest width suitable. You can selectively make enumerations smaller by using:

1
2
3
typedef enum __attribute__ ((__packed__)) {
    ...
} myEnum_t;

Max Values

There is no compiler syntax or language feature to get the number of elements in an enumeration at compile time. This can be useful information, you may want to do things like:

  • Iterate over every value in an enumeration.
  • Pick a random value from an enumeration.
  • Continue another enumeration from where a previous one left off (to guarantee unique numbers across many enumerations).

A common way of doing this is to add a value to the end of the enumeration calling something like MAX_VALUE. If it is the last the entry in the enumeration and there are no “gaps” in your enumeration (which is only possible if you manually assign numbers) then MAX_VALUE will equal the number of members in the enumeration.


Authors

Geoffrey Hunter

Dude making stuff.

Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License .

Related Content:

Tags

comments powered by Disqus