了解状态机之前先掌握跳转表

目录

为什么要写这篇

程序运行结果

跳转表主体代码

main函数代码

完整代码


为什么要写这篇

本来打算写篇关于状态机的文章,相关的理论知识已经写得差不多了,但是关于代码的,还没怎么准备,准备代码的过程中,看到自己之前练习的一个代码文件,是关于跳转表的,因为我想写的代码是基于跳转表的,而不是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;
}

 

 

上一篇:redis分布式锁 vs 双写一致性


下一篇:lua+redis