![]() | ||||||
|
||||||
| ||||||
Nuvation HEADLINES ![]()
| Writing Code for the Future When C switch statements go big, consider a lookup table Jeremy Schrage Embedded Systems Engineer Nuvation There are an infinite number of ways to write code that will be functionally compliant with specifications. Choosing which path to take can have important effects on the ability to make future changes to the software. Even in the absence of changes, a readable design is optimal for a new user to quickly understand what the code is doing. One example where two ways can have much different outcomes is the large switch statement in C. A switch statement is often used to provide a single decision multiple execution paths. You can have an endless number of cases, and some cases may share the same execution path. The switch statement is often used to "clean up" multiple if-else's. Example: Myfunc() { ... switch(myMessageID) { case HELLO: case HI: doWelcome(); break; case GOODBYE: case LATER: doWave(); break; case HELPME: doHelp(); break; default: errorProcess(); } ... } However, the switch statement may need to get cleaned up if there are multiple cases doing something simple like calling a function or setting one of many modes. One way to accomplish this is through a lookup table. Example: Here is a typedef of the struct used in the table: typedef struct HOST_FUNC { uchar command; uchar NumExtraBytes; void * p_hostFunc; } HOST_FUNC; Here is the table itself, any array of structs: HOST_FUNC arrHOST_FUNCtable[] = { WRITE_REG, 2, writeReg, READ_REG, 1, readReg, OR_REG, 2, orReg }; Here is a utility function, used to parse out an element in the table: void* HostFunc_findFunction( uchar command ) { HOST_FUNC* HOST_FUNCp; HOST_FUNCp = &arrHOST_FUNCtable[0]; while( HOST_FUNCp->command != END_OF_TABLE ) { if( command == HOST_FUNCp->command ) { return HOST_FUNCp->p_hostFunc; } HOST_FUNCp++; } return NULL; } Here is how it would be used: Myfunc() { ... pCommandFunc = (uchar (*)(uchar*))HostFunc_findFunction(myMessageID); if ( pCommandFunc == NULL ) { // uh oh errorHandle(); return; } status = ((uchar (*)(void) ) pCommandFunc)(); ... } I find that when processing message commands, for example, a lookup table works well. The lookup table can be in a separate file, along with the utility functions required to use it. Now, one downside to this approach is execution time. There will be extra pushes and pops as the utility functions are called and the desired data is retrieved. Another is code size. The table and utility functions will take up space. But in most cases, a few cycles and bytes aren't critical. There are many advantages to the lookup table: 1. Where there are a large number of commands, the switch statement that it replaces could be huge. Readability is increased where the utility functions are used. 2. No longer prone to errors from falling through cases (without breaks). 3. Additional cases can be easily added to the lookup table. 4. If additional elements need to be added to the structure, they can be added without too much trouble. 5. Your code is loosely coupled, yet highly cohesive. The table itself and utility functions are in another file. The calling function accesses the table via utility functions and doesn't know explicit details. Try one in your code today! · To subscribe yourself or a friend, please click here. · Questions? Comments? Send us your feedback. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
GO TO NUVATION.COM
Copyright © Nuvation Research Corporation 2003. All rights reserved. Privacy Policy | About Nuvation |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||