C Programming allows a great degree of freedom when a software is designed using it. It allows nesting of simple constructs to form a complex constructs to establish desired functionality.

These designs usually work fine. They shall be logically correct. But when building a large piece of software which will be maintained across time and space, some of these practices are more prone to error. When building Safety critical applications it is essential to avoid such complex constructs to keep the software less error prone and more safe.

One such complex construct is Nested-switch blocks (Switch within a Switch or If-Else within a Switch). C programming allows Nested-switch programming and the compiler works just fine. However the Nested-switch blocks are not recommended according to safe-programming guideliness. MISRA-C, the automotive safe programming guideline does not allow Nested-swtich blocks.

When faced with such scenario, it is necessary to mitigate the complex construct with some simple design or re-structure the code to eliminate the scenario. Often, along with safety, these approaches reduce the code size and increase the speed too.

In this article, lets see a pseudo-code on how to eliminate the Nested-switch blocks with a simpler code.


Consider a user menu based application, where it is required to perform a function based on the user selected menu options. The application shall present the user with a set of main-menu options and for each main-menu option a set of sub-menu options are also presented.


The user shall select a menu option and then a sub-menu option. The selected options are stored under enum variables,
mState smState


typedef enum { 
MenuState1 = 0,
MenuState2,
MenuState3,
} MenuStates;

typedef enum {
MenuSubState1 = 0,
MenuSubState2,
MenuSubState3,
MenuSubState4,
} MenuSubStates;

MenuStates mState;
MenuSubStates smState;

Now let us assume that the following functions shall be executed based on the selected main-menu and sub-menu states.

MenuState1 -> MenuSubState1 -> Task11()
MenuState1 -> MenuSubState2 -> Task12()
MenuState1 -> MenuSubState3 -> Task13()
MenuState1 -> MenuSubState4 -> Task14()

MenuState2 -> MenuSubState1 -> Task21()
MenuState2 -> MenuSubState2 -> No Action
MenuState2 -> MenuSubState3 -> Task23()
MenuState2 -> MenuSubState4 -> Task24()

MenuState3 -> MenuSubState1 -> Task31()
MenuState3 -> MenuSubState2 -> Task32()
MenuState3 -> MenuSubState3 -> Task33()
MenuState3 -> MenuSubState4 -> No Action

The above scenario shall be designed using Nested-Switch blocks as below,

switch (mState)
{
case MenuState1 :
   switch (smState)
   {
        case MenuSubState1:
                Task11();
                break;
        case MenuSubState2:
                Task12();
                break;
        case MenuSubState3:
                Task13();
                break;
        case MenuSubState4:
                Task14();
                break;
        default :
                break;
   }
break;

case MenuState2 :
   switch (smState)
   {
        case MenuSubState1:
                Task21();
                break;
        case MenuSubState3:
                Task23();
                break;
        case MenuSubState4:
                Task24();
                break;
         default :
                break;
   }
break;

case MenuState3 :
   switch (smState)
   {
        case MenuSubState1:
                Task31();
                break;
        case MenuSubState2:
                Task32();
                break;
        case MenuSubState3:
                Task33();
                break;
        default :
                break;
   }
break;

default :
break;
}


In the above code, the respective task is performed based on the values of mState (Main-menu option) and smState (sub-menu option).

It is evident from the above code that a nested-switch implementation is complex. And the code size only increases with more states. Maintaining such a code is tedious and would require complete re-implementation at times.

Therefore the above code should be replaced with an alternative implementation for simplicity and scaling. A better and safer approach for the above scenario is to use a Multi-dimension Array based implementation.

The Nested switch implementation shall be replaced with a multi-dimension array implementation with following considerations,
  • Create a multi-dimension array (dimension = Nesting level + 1). In this case the nesting level is 1. Hence a 2D array.
  • Considering the 2 state variables (mState and smState) as indexes, fill the Function pointers as array values.
  • Modify the enum declarations to add an additional value to indicate the size.
  • For cases where no action is to be done, fill with NULL.
The enum declarations and the code will look like below,

typedef enum {
MenuState1 = 0, 
MenuState2, 
MenuState3,
MenuStateSize
} MenuStates;

typedef enum {
MenuSubState1 = 0,
MenuSubState2,
MenuSubState3,
MenuSubState4,
MenuSubStateSize
} MenuSubStates;

MenuStates mState;
MenuSubStates smState;

void (* const TaskTable[MenuStateSize][MenuSubStateSize])(void) = {
       {TASK11, TASK12, TASK13, TASK14},
       {TASK21, NULL, TASK23, TASK24},
       {TASK31, TASK32, TASK33, NULL }
};


if(TaskTable[mState][smState] != NULL) //Check for NULL
{
           (*TaskTable[mState][smState])(); /* Calls the appropriate Task function based on the main-menu and sub-menu states. */
}



In above code, nested switch case is replaced by an array of function-pointers.

Note : It is essential to check for NULL and also the array indexes are within range to avoid issues.

Though the code reduces complexity, the usage of pointers shall sometimes be not liked.
So the developer shall decide the method desired based on his/her own requirements.




Thank you !