To switch or not to switch…

Nigel Jones makes a compelling argument against the use of switch statements. A compiler has roughly two options for implementing a switch statement: 1) the equivalent of a number of if – else if – else statements or 2) a jump table. For a small number of cases option 1) may be more efficient. If you have a large number of cases option 2) is likely to be more efficient. Some compilers only support one option, others apply heuristics to choose between the alternatives. The bottom line of Nigel’s argument is the actual code size of a switch statement is rather unpredictable. This can be especially confusing if you remove a case and find the code size increases due to the compiler now favoring option 1) over option 2). However, the code size for a switch statement is always comparable or less than an equivalent series of if – else if – else statements. For me, that is good enough to generously apply the switch statements in my code. Furthermore, I find the syntax of the statement aesthetically pleasing and thus easy to read. Forgetting an ‘else’ in a sequence of if – else if – else statements can be a nasty bug to find. I find the equivalent in a switch statement, a missing break, much harder to overlook. But hold on a second, what if you implement a jump table yourself? As the following snippet shows, a jump table is also very easy to read.

typedef enum {
    action_turnOn      = 0,
    action_turnOff     ,
    action_dimUp       ,
    action_dimDown     ,
    action_stopDimming
} action_t;

static void TurnOn(void);
static void TurnOff(void);
static void DimUp(void);
static void DimDown(void);
static void StopDimming(void);

//
// SWITCH STATEMENT
//
void ExecuteAction(action_t action) {
    switch( action ) {
        case action_turnOn      : TurnOn()     ; break;
        case action_turnOff     : TurnOff()    ; break;
        case action_dimUp       : DimUp()      ; break;
        case action_dimDown     : DimDown()    ; break;
        case action_stopDimming : StopDimming(); break;
        default:
            break;
    }
}

//
// IF - ELSE IF - ELSE SEQUENCE
//
void ExecuteAction(action_t action) {
    if ( action == action_turnOn ) {
        TurnOn();
    } else if ( action == action_turnOff ) {
        TurnOff();
    } else if ( action == action_dimUp ) {
        DimUp();
    } else if ( action == action_dimDown ) {
        DimDown();
    } else if ( action == action_stopDimming ) {
        StopDimming();
    }
}

//
// JUMP TABLE
//
void ExecuteAction(action_t action) {
    void (*jumpTable[])(void) = {
        TurnOn         ,
        TurnOff        ,
        TurnDimUp      ,
        TurnDimDown    ,
        TurnStopDimming
    };
    
    jumpTable[action]();
}

Unfortunately the compiler has more freedom in implementing a jump table than you have at the source level. You will have to create functions and reference them by pointers, which prevents the compiler from inlining them. The functions themselves may cause some administrative overhead. If the functions are inlined, which can be the case in a switch statement, it is easier for the compiler to exploit common parts and do a better job at optimizing for small code size. Not all jumps are equal, a local jump within a function may be less costly than a function call. The result is that a jump table is probably more costly in terms of code size than a switch statement or an if – else is – else sequence. That said, jump tables CAN be a good alternative. Switch statements only work with constant numbers. With some modifications jump tables can work with other data types as well. Measure what works best for you and your platform. At least you now have the choice between a sequence of if – else if – else statements, a switch statement or a jump table.