目录
为什么要写这篇
本来打算写篇关于状态机的文章,相关的理论知识已经写得差不多了,但是关于代码的,还没怎么准备,准备代码的过程中,看到自己之前练习的一个代码文件,是关于跳转表的,因为我想写的代码是基于跳转表的,而不是switch...case 或 if...else,觉得在状态机的代码准备好之前可以先写一篇关于跳转表的。
可能之前没有听说过跳转表,这两个奇奇怪怪的概念(状态机,跳转表)也是基于已有的C语言概念的,比如for循环,比如指针(函数指针),结构体和结构体数组,枚举类型。
跳转表就是使用标识符和函数指针做成的结构体数组,通过对结构体数组进行遍历,查找到对应标识符,就调用对应的函数指针执行相应函数。下面这个函数是查找标识符在合理范围内直接调用对应的函数指针。
程序运行结果
讲解的例子是实现简单的四则运算,涉及到的参数可以通过命令行传入。这是我看的公众号文章里的代码,重写了main函数的实现。
可命令行传入参数的main函数定义
int main(int argc, char *argv[])
编译完成后在命令行输入:JumpTable.exe 23 x 5 = 然后回车,即可得到相应运算结果
跳转表主体代码
/* 将操作定义为枚举类型 */
typedef enum
{
OP_ADD = 0, //执行操作:加法
OP_SUB, //执行操作:减法
OP_MUL, //执行操作:乘法
OP_DIV, //执行操作:除法
} OP_TYPE;
/* 入参为double, 出参为double的函数指针 */
typedef double (*OP_FUNC)(double, double);
typedef struct OP_STRUCT
{
OP_TYPE opType; //操作类型
OP_FUNC opFun; //操作函数
} OP_STRUCT;
/*加减乘除处理函数*/
double ADD(double op1, double op2)
{
return op1 + op2;
}
double SUB(double op1, double op2)
{
return op1 - op2;
}
double MUL(double op1, double op2)
{
return op1 * op2;
}
double DIV(double op1, double op2)
{
return op1 / op2;
}
/* 函数跳转表 */
static OP_STRUCT g_opStruct[] =
{
{OP_ADD, ADD},
{OP_SUB, SUB},
{OP_MUL, MUL},
{OP_DIV, DIV},
};
/* 最大操作数量 */
static int g_opNum = sizeof(g_opStruct) / sizeof(OP_STRUCT);
/**
* calc
* @brief 四则运算函数
* @param op 参数描述: 操作符对应值
* @param op1 参数描述: 第一操作数
* @param op2 参数描述: 第二操作数
* @retval double 返回值描述: 运算结果
*/
double calc(int op, double op1, double op2)
{
if (op >= g_opNum || op < 0)
{
printf("unknow operation \n");
return 0;
}
/* 根据操作类型直接选择操作函数 */
return g_opStruct[op].opFun(op1, op2);
}
main函数代码
主要的都是命令行参数的判断,唯一和自己实现的函数有关的是double result = calc(op, op1, op2); calc函数就用到了跳转表。
int main(int argc, char *argv[])
{
/* 检查参数个数 */
if (argc != 5)
{
printf("please refer to: JumpTable.exe 2 x 3 = \n");
return 0;
}
/* 获取第一个参数,用于运算 */
double op1 = atof(argv[1]);
/* 获取第二个参数,用于运算 */
int op = -1;
if(('+' == argv[2][0]) && ('\0' == argv[2][1]))
{
op = 0;
}else if(('-' == argv[2][0]) && ('\0' == argv[2][1]))
{
op = 1;
}else if(('x' == argv[2][0]) && ('\0' == argv[2][1]))
{
op = 2;
}else if(('/' == argv[2][0]) && ('\0' == argv[2][1]))
{
op = 3;
}
if(op == -1)
{
printf("operator is not one of '+','-','x' and '/' \n");
return 0;
}
/* 获取第三个参数,用于运算 */
double op2 = atof(argv[3]);
printf("op1:%.1f, op: %s, op2:%.1f \n", op1, argv[2], op2);
/* 获取第四个参数,用于维持形式 */
if(('?' == argv[4][0]) || ('=' == argv[4][0]) && ('\0' == argv[4][1]))
{
double result = calc(op, op1, op2);
printf("result is: %.1f \n", result);
}else
{
printf("Do you want to know the result? \n");
printf("please refer to: JumpTable.exe 2 x 3 = \n");
}
return 0;
}
完整代码
#include <stdio.h>
#include <stdlib.h>
/* 将操作定义为枚举类型 */
typedef enum
{
OP_ADD = 0, //执行操作:加法
OP_SUB, //执行操作:减法
OP_MUL, //执行操作:乘法
OP_DIV, //执行操作:除法
} OP_TYPE;
/* 入参为double, 出参为double的函数指针 */
typedef double (*OP_FUNC)(double, double);
typedef struct OP_STRUCT
{
OP_TYPE opType; //操作类型
OP_FUNC opFun; //操作函数
} OP_STRUCT;
/*加减乘除处理函数*/
double ADD(double op1, double op2)
{
return op1 + op2;
}
double SUB(double op1, double op2)
{
return op1 - op2;
}
double MUL(double op1, double op2)
{
return op1 * op2;
}
double DIV(double op1, double op2)
{
return op1 / op2;
}
/* 函数跳转表 */
static OP_STRUCT g_opStruct[] =
{
{OP_ADD, ADD},
{OP_SUB, SUB},
{OP_MUL, MUL},
{OP_DIV, DIV},
};
/* 最大操作数量 */
static int g_opNum = sizeof(g_opStruct) / sizeof(OP_STRUCT);
/**
* calc
* @brief 四则运算函数
* @param op 参数描述: 操作符对应值
* @param op1 参数描述: 第一操作数
* @param op2 参数描述: 第二操作数
* @retval double 返回值描述: 运算结果
*/
double calc(int op, double op1, double op2)
{
if (op >= g_opNum || op < 0)
{
printf("unknow operation \n");
return 0;
}
/* 根据操作类型直接选择操作函数 */
return g_opStruct[op].opFun(op1, op2);
}
int main(int argc, char *argv[])
{
/* 检查参数个数 */
if (argc != 5)
{
printf("please refer to: JumpTable.exe 2 x 3 = \n");
return 0;
}
/* 获取第一个参数,用于运算 */
double op1 = atof(argv[1]);
/* 获取第二个参数,用于运算 */
int op = -1;
if(('+' == argv[2][0]) && ('\0' == argv[2][1]))
{
op = 0;
}else if(('-' == argv[2][0]) && ('\0' == argv[2][1]))
{
op = 1;
}else if(('x' == argv[2][0]) && ('\0' == argv[2][1]))
{
op = 2;
}else if(('/' == argv[2][0]) && ('\0' == argv[2][1]))
{
op = 3;
}
if(op == -1)
{
printf("operator is not one of '+','-','x' and '/' \n");
return 0;
}
/* 获取第三个参数,用于运算 */
double op2 = atof(argv[3]);
printf("op1:%.1f, op: %s, op2:%.1f \n", op1, argv[2], op2);
/* 获取第四个参数,用于维持形式 */
if(('?' == argv[4][0]) || ('=' == argv[4][0]) && ('\0' == argv[4][1]))
{
double result = calc(op, op1, op2);
printf("result is: %.1f \n", result);
}else
{
printf("Do you want to know the result? \n");
printf("please refer to: JumpTable.exe 2 x 3 = \n");
}
return 0;
}