Make your code more elegant programming skills - jump table (top)

Reprinted from: https://www.yanbinghu.com/2019/01/20/6807.html?nsukey=kFLEF1Ek4bV4HLe0Dqum%2BJaiMZLqsvyHCf%2Fm%2F1cOp99fzJETfwdsG%2FSU7vq2jiX0Twk3oCAnmutbWO0p3X58iVsXZlZPDxkfdNINr9iD9pz6mIdchN6O91qgGQL98dHEN4pFLv6yogD9tVWcoeviUtjeiGqS4VdL8lrvAQbnEI4%3D

Personally I feel very good article, so the top, reprint

Foreword

Earlier we talked about the " function pointer ", today we see a programming technique - function jump table. We first look at how to implement a simple calculator.

initial version

Let's implement a simple calculator, first of all what we can think of way? The switch statement or if else statements. Yes, the beginner will think of two ways, let's look at this implementation. Here we choose the switch statement, a definition of the type of operation, the user selects the type of operation to match the type of operation, corresponding to the selected handler processes, calc1.c code is as follows:

/*calc1.c*/ 
#include <stdio.h> 
#include <stdlib.h> 
/ * operation is defined as an enumeration type * / 
typedef enum 
{ 
    OP_ADD = 0, 
    OP_SUB, 
    OP_MUL, 
    OP_DIV, 
} op_type; 
/ * arithmetic processing functions * / 
Double the ADD (Double OP1, OP2 Double) 
{ 
    return OP1 + OP2; 
} 
Double the SUB (Double OP1, OP2 Double) 
{ 
    return OP1-OP2; 
} 
Double the MUL (Double OP1, OP2 Double) 
{ 
    return * OP2 OP1; 
} 
Double the DIV (Double OP1, OP2 Double) 
{ 
    return OP1 / OP2; 
} 
Double Calc (int OP, Double OP1, OP2 Double) 
{
    / * Use Switch, according to the type of operation, select Options * / 
    Double Result = 0; 
    Switch (OP) 
    { 
        Case OP_ADD: 
        { 
            Result = the ADD (OP1, OP2); 
            BREAK; 
        } 
        Case OP_SUB: 
        { 
            Result = the SUB (OP1, OP2 ); 
            BREAK; 
        } 
        Case OP_MUL: 
        { 
            Result = the MUL (OP1, OP2); 
            BREAK; 
        } 
        Case OP_DIV: 
        { 
            Result = the DIV (OP1, OP2); 
            BREAK; 
        } 
        default: 
        {
            printf("unsupport opration\n");
            break;
        }
    }
    return result;
}

int main(int argc,char *argv[])
{  
    if(4 > argc)
    {
        printf("usage:op num1 num2\n");
        printf("op[0:add,1:sub,2:mul;3:div]\n");
        return 0;
    }
    int op = atoi(argv[1]);
    double op1 = atof(argv[2]);
    double op2 = atof(argv[3]);
    printf("op:%d,op1:%.1f,op2:%.1f\n",op,op1,op2);
    double result = calc(op,op1,op2);
    printf("result is %.1f\n",result);
    return 0;
}

  My results are as follows:

PS C:\Users\NL\Desktop\ziln\ctest> .\calc.exe 0 2 3
op:0,op1:2.0,op2:3.0
result is 5.0

It appears to be very perfect ~ ~

Compiler switch case removed optimized , this design approach has several disadvantages:

  • When the operation increases, the code increases, case statements will become redundant.
  • Operation increases, increased branching, the processing corresponding to the operation time will increase.
  • Maintainability poor.

We observe the code will find that each additional operation, you need to add a branch, when the operation more and more time to calc function will become lengthy and difficult to maintain. And if no compiler optimizations, because the final match before finding each case statement need to be performed, and therefore could lead to longer run time.

Function jump table version

Since each operation corresponds to a function, you can define an array of function pointers, and each index value corresponds to an operation, just know the value of the subscript, quickly find the corresponding function. We all know that the array subscript access data efficiency is very high. This version implemented as follows:

 

#include <stdio.h> 
#include <stdlib.h> 
/ * operation is defined as an enumeration type * / 
typedef enum 
{ 
    OP_ADD = 0, 
    OP_SUB, 
    OP_MUL, 
    OP_DIV, 
} op_type; 
/ * the reference as a double, the reference a double function pointer * / 
typedef double (* OP_FUNC) (double, double); 
typedef struct OP_STRUCT 
{ 
    op_type optype; // operation type 
    OP_FUNC opFun; // operation functions 
} OP_STRUCT; 
/ * arithmetic processing function and calc1. same as C, is omitted here, are free to add * / 
/ * function jump table * / 
static OP_STRUCT g_opStruct [] = 
{ 
    {OP_ADD, the ADD}, 
    {OP_SUB, the SUB}, 
    {OP_MUL, the MUL}, 
    {OP_DIV, the DIV}, 
}; 
/ * maximum number of operations * /
int = the sizeof g_opNum static (g_opStruct) / the sizeof (OP_STRUCT); 
Double Calc (int OP, Double OP1, OP2 Double) 
{ 
    IF (OP> OP = g_opNum || <0) 
    { 
        the printf ( "unknow opration \ n-"); 
        0 return; 
    } 
    / * * function direct selective operation / action type 
    return g_opStruct [OP] .opFun (OP1, OP2); 
} 

/ * main calc1.c the same function is omitted here * / 
int main (int argc, char * the argv []) 
{ 
    IF (. 4> argc) 
    { 
        the printf ( "Usage: OP num1 num2 \ n-"); 
        the printf ( "OP [0: the Add,. 1: Sub, 2: MUL;. 3: div] \ n-" ); 
        return 0; 
    } 
    int OP = atoi (the argv [. 1]);  
    Double the atof OP1 = (the argv [2]);
    Double the atof OP2 = (the argv [. 3]);
    printf("op:%d,op1:%.1f,op2:%.1f\n", op, op1, op2);
    double result = calc(op, op1, op2);
    printf("result is %.1f\n", result);
    return 0;
}

  

calc functions, direct and select the desired operation processing function according to the operation type. Time complexity is O (1). Further, when it is desired to add one kind of operation, no need to modify calc function of operating to increase only in the function table g_opStruct. And a return value operation process is double, the double function of two parameters, the use of:

1
typedef double (*OP_FUNC)(double,double);

 

The function pointer is defined as the type used OP_FUNC, the latter aspect.

In addition, you can also see the calc function is very simple, the key code is only one line.

to sum up

There are many examples in this article can be optimized places, for example, 0 returns an exception, and the like may be treated as a result, the switch statement herein except for the jump table and a simple example. And for the same type of branching, can consider ways to use the jump table, use a jump table also point to note is the array bounds .
The jump table is just an idea, it is not in all cases can replace switch statement, decide whether to require the use of the actual situation.

Think

Why in the description of the first version of the simple calculator when stressed: remove compiler switch be optimized case?

Guess you like

Origin www.cnblogs.com/CodeWorkerLiMing/p/11867508.html