LV030-函数指针的应用
前边已经学习了函数指针的概念和基本的应用,本篇笔记主要是函数指针的应用,在这里需要完成一个命令执行的过程。
一、命令处理函数
1. 函数定义
接收到命令的时候,需要使用函数指针指向对应的命令处理函数,我们的命令处理函数如下:
c
unsigned int func_name(int arg, int *pParam, void *pBuf)
{
// ... ...
}【参数说明】
- arg :int类型参数,调用命令处理函数时传入。
- pParam :int类型指针变量,调用命令处理函数时传入。
- pBuf :void 类型指针变量,指向一块内存区域,用于接收命令下达时命令中的信息,可以自定义。
2. 函数声明
上边的函数定义之后肯定是需要声明的,如下所示:
c
unsigned int func_name(int arg, int *pParam, void *pBuf);会发现,这样是有些长,当命令多起来的时候,他们唯一的区别就是函数名不同,这样我们可以使用一个宏定义,定义一下函数的声明格式:
c
#define HOST_CMD_PROCESS_FUNC(_name_) unsigned int _name_(int arg, int *pParam, void *pBuf) // 方便定义命令处理函数的函数名【注意】注意这里不要写成下边这样:
c
#define HOST_CMD_PROCESS_FUNC(_name_) (unsigned int _name_(int arg, int *pParam, void *pBuf))这样可能会报以下问题:
shell
error: expected identifier or ‘(’ before ‘unsigned’
#define HOST_CMD_PROCESS_FUNC(_name_) (unsigned int _name_(int arg, int *pParam, void *pBuf))【声明实例】
c
HOST_CMD_PROCESS_FUNC(HostTest1);这就等价于:
c
unsigned int HostTest1(int arg, int *pParam, void *pBuf);3. 函数指针定义
当我们需要调用命令处理函数的时候,就需要用到函数指针,我们可以定义如下:
c
typedef unsigned int (*Host_Cmd_Process_Func)(int arg, int *pParam, void *pBuf); // 定义指向主机命令处理函数的指针(1)(*Host_Cmd_Process_Func)中,Host_Cmd_Process_Func是一个指针变量;
(2)再看后边的括号,里边有三个参数,所以Host_Cmd_Process_Func可以指向一个带有三个参数的函数;
(3)最后看前边的unsigned int,说明函数返回值为 unsigned int 类型;
总的来说,Host_Cmd_Process_Func 可以指向一个返回值为 unsigned int 类型,含有三个参数的函数。
【使用实例】
c
Host_Cmd_Process_Func pFunc = NULL;
pFunc = (Host_Cmd_Process_Func)HostTest1;
pFunc(arg, (int *)&pParam, (void *)&cmdBuf);二、命令信息
1. 命令描述
每一条命令都包含以下信息:
c
// 命令描述结构体——存放在命令数组中的每条命令要包含的信息数据
typedef struct
{
unsigned long long value1; // 8字节 64位
unsigned long long value2; // 8字节 64位
Host_Cmd_Process_Func pFunc; // 主机命令对应的处理函数
} HOST_CMD_DETAIL;2. 命令信息组合
我们定义一个宏,来组合在写命令的时候想给命令的参数:
c
// 命令数组的成员组合——将数据组合,方便存放在命令数组中
#define MAKE_HOST_CMD(_wait_, _type_, _bPara_, _bRetPara_, _buf_, _retBuf_, _func_) \
{ \
(_wait_ & 0xffff) | ((_type_ & 3) << 16) | ((_bPara_ & 1) << 18) | ((_bRetPara_ & 1) << 19), \
((_retBuf_ & 0xffff) << 16) | (_buf_ & 0xffff), \
_func_ \
}3. 命令数组定义
我们收到命令后,回到这些数组中寻找对应的命令信息,命令的处理函数也将在这里获取,这里:
c
// 保存每一条命令信息的数组
HOST_CMD_DETAIL hostCmdDetail[] =
{
// 0,100
MAKE_HOST_CMD(10000, 0, 1, 0, 0, 0, (Host_Cmd_Process_Func)HostTest1),
// 1,101
MAKE_HOST_CMD(10000, 0, 1, 0, 0, 0, (Host_Cmd_Process_Func)HostTest2),
};
// 保存每一条命令信息的数组
HOST_CMD_DETAIL smartHostCmdDetail[] =
{
// 0,200
MAKE_HOST_CMD(10000, 0, 1, 0, 0, 0, (Host_Cmd_Process_Func)SmartHostTest1),
// 1,201
MAKE_HOST_CMD(10000, 0, 1, 0, 0, 0, (Host_Cmd_Process_Func)SmartHostTest2),
};4. 命令编号定义
c
// 命令的编号——每个命令的编号
typedef enum
{
HOST_CMD_TEST1 = HOST_CMD_MIN, // 100
HOST_CMD_TEST2, // 101
HOST_CMD_TEST3, // 102
// ... ...
HOST_CMD_MAX, // 主机命令最大编号,在最大编号上边新增命令编号
SMART_HOST_CMD_TEST1 = SMART_HOST_CMD_MIN, // 200
SMART_HOST_CMD_TEST2, // 201
SMART_HOST_CMD_TEST3, // 202
// ... ...
SMART_HOST_CMD_MAX, // SMART主机命令最大编号,在最大编号上边新增命令编号
}HOST_CMD;5. 命令区分
我们会有不同的命令,我们通过不同的值区间:
c
#define HOST_CMD_MIN 100 // 主机命令最小的命令编号,只有大于等于此值的命令编号才会被识别为主机命令
#define SMART_HOST_CMD_MIN 200 // SMART主机命令最小的命令编号,只有大于等于此值的命令编号才会被识别为SMART主机命令三、实例
1. 源码实现
1.1 sys_cmd_info.h
c
#ifndef __SYS_CMD_INFO_H__
#define __SYS_CMD_INFO_H__
#define HOST_CMD_MIN 100 // 主机命令最小的命令编号,只有大于等于此值的命令编号才会被识别为主机命令
#define SMART_HOST_CMD_MIN 200 // SMART主机命令最小的命令编号,只有大于等于此值的命令编号才会被识别为SMART主机命令
#define GET_CMD_FUNC(_cmd_) ((_cmd_).pFunc) // 获取数组中元素的命令处理函数成员
#define HOST_CMD_PROCESS_FUNC(_name_) (unsigned int _name_(int arg, int *pParam, void *pBuf)) // 方便定义命令处理函数的函数名
typedef unsigned int (*Host_Cmd_Process_Func)(int arg, int *pParam, void *pBuf); // 定义指向主机命令处理函数的指针
// 命令数组的成员组合——将数据组合,方便存放在命令数组中
#define MAKE_HOST_CMD(_wait_, _type_, _bPara_, _bRetPara_, _buf_, _retBuf_, _func_) \
{ \
(_wait_ & 0xffff) | ((_type_ & 3) << 16) | ((_bPara_ & 1) << 18) | ((_bRetPara_ & 1) << 19), \
((_retBuf_ & 0xffff) << 16) | (_buf_ & 0xffff), \
_func_ \
}
// 命令描述结构体——存放在命令数组中的每条命令要包含的信息数据
typedef struct
{
unsigned long long value1; // 8字节 64位
unsigned long long value2; // 8字节 64位
Host_Cmd_Process_Func pFunc; // 主机命令对应的处理函数
} HOST_CMD_DETAIL;
// 命令下达时携带的数据
typedef struct
{
int a;
char b;
} _CMD_DATA;
#endif1.2 sys_cmd.h
c
#ifndef __SYS_CMD_H__
#define __SYS_CMD_H__
#include "sys_cmd_info.h"
// 命令的编号——每个命令的编号
typedef enum
{
HOST_CMD_TEST1 = HOST_CMD_MIN, // 100
HOST_CMD_TEST2, // 101
HOST_CMD_TEST3, // 102
// ... ...
HOST_CMD_MAX, // 主机命令最大编号,在最大编号上边新增命令编号
SMART_HOST_CMD_TEST1 = SMART_HOST_CMD_MIN, // 200
SMART_HOST_CMD_TEST2, // 201
SMART_HOST_CMD_TEST3, // 202
// ... ...
SMART_HOST_CMD_MAX, // SMART主机命令最大编号,在最大编号上边新增命令编号
}HOST_CMD;
// 命令处理函数的声明
HOST_CMD_PROCESS_FUNC(HostTest1); // unsigned int HostTest1(int chan, int *pParam, void *pBuf);
HOST_CMD_PROCESS_FUNC(HostTest2); // unsigned int HostTest2(int chan, int *pParam, void *pBuf);
HOST_CMD_PROCESS_FUNC(SmartHostTest1); // unsigned int SmartHostTest1(int chan, int *pParam, void *pBuf);
HOST_CMD_PROCESS_FUNC(SmartHostTest2); // unsigned int SmartHostTest2(int chan, int *pParam, void *pBuf);
// 保存每一条命令信息的数组
HOST_CMD_DETAIL hostCmdDetail[] =
{
// 0,100
MAKE_HOST_CMD(10000, 0, 1, 0, 0, 0, (Host_Cmd_Process_Func)HostTest1),
// 1,101
MAKE_HOST_CMD(10000, 0, 1, 0, 0, 0, (Host_Cmd_Process_Func)HostTest2),
};
// 保存每一条命令信息的数组
HOST_CMD_DETAIL smartHostCmdDetail[] =
{
// 0,200
MAKE_HOST_CMD(10000, 0, 1, 0, 0, 0, (Host_Cmd_Process_Func)SmartHostTest1),
// 1,201
MAKE_HOST_CMD(10000, 0, 1, 0, 0, 0, (Host_Cmd_Process_Func)SmartHostTest2),
};
#endif1.3 sys_cmd.c
c
#include <stdio.h>
#include <stdlib.h>
#include "debug_printf.h"
#include "sys_cmd.h"
int main(int argc, const char *argv[])
{
// 命令编号与命令的索引
int cmd = 0;
int cmdIndex = 0;
// 传递给命令处理函数的参数
int arg = 0;
int pParam = 0;
_CMD_DATA cmdBuf = {0, '0'};
// 指向命令处理函数的指针变量
Host_Cmd_Process_Func pFunc = NULL;
// 指向命令数组的指针变量
HOST_CMD_DETAIL *pCmdDetail = NULL;
// 命令的相关数量计算
int host_cmd_num = HOST_CMD_MAX - HOST_CMD_MIN;
int smart_host_cmd_num = SMART_HOST_CMD_MAX - SMART_HOST_CMD_MIN;
int host_cmd_func_num = sizeof(hostCmdDetail)/sizeof(hostCmdDetail[0]);
int smart_host_cmd_func_num = sizeof(smartHostCmdDetail)/sizeof(smartHostCmdDetail[0]);
HKPRT("HOST_CMD:num %d,func %d\n", host_cmd_num, host_cmd_func_num);
HKPRT("SMART_HOST_CMD:num %d,func %d\n", smart_host_cmd_num, smart_host_cmd_func_num);
// 命令的查找与处理
cmd = atoi(argv[1]);
if((cmd >= HOST_CMD_MIN) && (cmd < HOST_CMD_MAX))
{
arg = 1;
pParam = 1;
cmdBuf.a = 100;
cmdBuf.b = 'a';
pCmdDetail = hostCmdDetail;
cmdIndex = cmd - HOST_CMD_MIN;
if(cmdIndex >= host_cmd_func_num) // 判断一下防止访问数组越界
{
HKPRTE("This function is not exist in hostCmdDetail[%d]!!! cmd:%d,cmdIndex:%d\n", host_cmd_func_num, cmd, cmdIndex);
return -1;
}
}
else if((cmd >= SMART_HOST_CMD_MIN) && (cmd < SMART_HOST_CMD_MAX))
{
arg = 2;
pParam = 2;
cmdBuf.a = 200;
cmdBuf.b = 'b';
pCmdDetail = smartHostCmdDetail;
cmdIndex = cmd - SMART_HOST_CMD_MIN;
if(cmdIndex >= smart_host_cmd_func_num) // 判断一下防止访问数组越界
{
HKPRTE("This function is not exist in smartHostCmdDetail[%d]!!! cmd:%d,cmdIndex:%d\n", smart_host_cmd_func_num, cmd, cmdIndex);
return -1;
}
}
else
{
HKPRTE("cmd number is invalid!!!\n");
return -1;
}
// 执行命令处理函数
pFunc = (Host_Cmd_Process_Func)(GET_CMD_FUNC(pCmdDetail[cmdIndex])); // hostCmdDetail
if(pFunc == NULL)
{
HKPRTE("This function is not exist!!! cmd:%d,cmdIndex:%d,pFunc:%p\n", cmd, cmdIndex, pFunc);
return -1;
}
pFunc(arg, (int *)&pParam, (void *)&cmdBuf);
return 0;
}
//unsigned int HostTest1(int arg, int *pParam, void *pBuf)
HOST_CMD_PROCESS_FUNC(HostTest1)
{
_CMD_DATA *p = (_CMD_DATA *)pBuf;
HKPRT("This is HostTest1!!!\n");
HKPRT("arg=%d,*pParam=%d,pBuf.a=%d,pBuf.b=%c\n", arg, *pParam, p->a, p->b);
return 0;
}
//unsigned int HostTest2(int arg, int *pParam, void *pBuf)
HOST_CMD_PROCESS_FUNC(HostTest2)
{
_CMD_DATA *p = (_CMD_DATA *)pBuf;
HKPRT("This is HostTest2!!!\n");
HKPRT("arg=%d,*pParam=%d,pBuf.a=%d,pBuf.b=%c\n", arg, *pParam, p->a, p->b);
return 0;
}
//unsigned int SmartHostTest1(int arg, int *pParam, void *pBuf)
HOST_CMD_PROCESS_FUNC(SmartHostTest1)
{
_CMD_DATA *p = (_CMD_DATA *)pBuf;
HKPRT("This is SmartHostTest1!!!\n");
HKPRT("arg=%d,*pParam=%d,pBuf.a=%d,pBuf.b=%c\n", arg, *pParam, p->a, p->b);
return 0;
}
//unsigned int SmartHostTest2(int arg, int *pParam, void *pBuf)
HOST_CMD_PROCESS_FUNC(SmartHostTest2)
{
_CMD_DATA *p = (_CMD_DATA *)pBuf;
HKPRT("This is SmartHostTest2!!!\n");
HKPRT("arg=%d,*pParam=%d,pBuf.a=%d,pBuf.b=%c\n", arg, *pParam, p->a, p->b);
return 0;
}1.4 debug_printf.h
c
#ifndef __DEBUG_PRINTF_H__
#define __DEBUG_PRINTF_H__
#include <stdio.h>
#define DEBUG_ENABLE 1 /* 是否开启调试信息 */
#define LOG_LEVEL DEBUG_ALL /* 调试信息显示级别 */
#define ERROR "ERROR" /* 错误 */
#define WARN "WARN " /* 警告 */
#define INFO "INFO " /* 信息 */
/* 颜色定义——字体颜色 */
#define CLS_ALL "\033[0m" /* 清除所有颜色 */
#define F_BLACK "\033[30m" /* 黑色字体 */
#define F_RED "\033[31m" /* 红色字体 */
#define F_GREEN "\033[32m" /* 绿色字体 */
#define F_YELLOW "\033[33m" /* 黄色字体 */
#define F_BLUE "\033[34m" /* 蓝色字体 */
#define F_PURPLE "\033[35m" /* 紫色字体 */
#define F_CYAN "\033[36m" /* 青色字体 */
#define F_WHITE "\033[37m" /* 白色字体 */
/* 颜色定义——背景颜色 */
#define B_BLACK "\033[40m" /* 黑色背景 */
#define B_RED "\033[41m" /* 红色背景 */
#define B_GREEN "\033[42m" /* 绿色背景 */
#define B_YELLOW "\033[43m" /* 黄色背景 */
#define B_BLUE "\033[44m" /* 蓝色背景 */
#define B_PURPLE "\033[45m" /* 紫色背景 */
#define B_CYAN "\033[46m" /* 青色背景 */
#define B_WHITE "\033[47m" /* 白色背景 */
/* 颜色定义——背景的字体 */
#define BLACK_RED "\033[30;41m" /* 红底黑字 */
#define BLACK_GREEN "\033[30;42m" /* 绿底黑字 */
#define BLACK_YELLOW "\033[30;43m" /* 黄底黑字 */
/* 调试等级枚举类型定义 */
enum DEBUG_LEVEL
{
DEBUG_OFF = 0,
DEBUG_ERROR = 1,
DEBUG_WARN = 2,
DEBUG_INFO = 3,
DEBUG_ALL = 4
};
//===========================================================================
/* 自定义类型和字体颜色 */
#define MYDEBUG(TYPE, COLOR, FMT, ARGS...) \
do \
{ \
if(DEBUG_ENABLE && (DEBUG_##TYPE <= LOG_LEVEL)) \
{ \
printf(COLOR); \
printf("[%s][%s:%s:%d]"FMT, TYPE, __FILE__, __FUNCTION__, __LINE__, ##ARGS); \
printf(CLS_ALL"\n"); \
} \
} while(0)
//===========================================================================
/* 平时调试使用 */
#include <string.h>
#include <time.h> // 时间函数用
#define filename(x) (strrchr(x,'/')?(strrchr(x,'/')+1):x)
#define NORMAL_DEBUG 1 // 注意使用下边两个宏需要自己添加换行,比较符合平时的习惯
// 获取时间函数
char *timeString(void)
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
struct tm *timeinfo = localtime(&ts.tv_sec);
static char timeString[30];
sprintf(timeString, "%.2d-%.2d %.2d:%.2d:%.2d",
timeinfo->tm_mon + 1,
timeinfo->tm_mday,
timeinfo->tm_hour,
timeinfo->tm_min,
timeinfo->tm_sec);
return timeString;
}
// 获取系统时间戳 单位 ms
int sys_pts_get_ms(void)
{
struct timespec tv;
long long lasttime = 0;
clock_gettime(CLOCK_MONOTONIC, &tv);
lasttime = tv.tv_sec * 1000 + tv.tv_nsec / (1000 * 1000);
return lasttime;
}
#define HKPRT(fmt...) \
do \
{ \
if(NORMAL_DEBUG) \
{ \
printf(F_YELLOW); \
printf("[%s][HK_LOG][%s:%d][%s]", timeString(), filename(__FILE__), __LINE__, __FUNCTION__); \
printf(CLS_ALL); \
printf(fmt); \
} \
} while(0)
#define HKPRTE(fmt...) \
do \
{ \
if(NORMAL_DEBUG) \
{ \
printf(F_RED); \
printf("[%s][HK_LOG][%s:%d][%s]", timeString(), filename(__FILE__), __LINE__, __FUNCTION__); \
printf(CLS_ALL); \
printf(fmt); \
} \
} while(0)
#endif2. 测试结果
我们通过以下命令编译:
shell
gcc sys_cmd.c -Wall运行结果如下:
c
sumu@virtual-machine:~/6temp/test$ ./a.out 101
[02-12 17:55:56][HK_LOG][01_sys_cmd.c:37][main]HOST_CMD:num 3,func 2
[02-12 17:55:56][HK_LOG][01_sys_cmd.c:38][main]SMART_HOST_CMD:num 3,func 2
[02-12 17:55:56][HK_LOG][01_sys_cmd.c:100][HostTest2]This is HostTest2!!!
[02-12 17:55:56][HK_LOG][01_sys_cmd.c:101][HostTest2]arg=1,*pParam=1,pBuf.a=100,pBuf.b=a
sumu@virtual-machine:~/6temp/test$ ./a.out 102
[02-12 17:55:59][HK_LOG][01_sys_cmd.c:37][main]HOST_CMD:num 3,func 2
[02-12 17:55:59][HK_LOG][01_sys_cmd.c:38][main]SMART_HOST_CMD:num 3,func 2
[02-12 17:55:59][HK_LOG][01_sys_cmd.c:51][main]This function is not exist in hostCmdDetail[2]!!! cmd:102,cmdIndex:2
sumu@virtual-machine:~/6temp/test$ ./a.out 103
[02-12 17:56:03][HK_LOG][01_sys_cmd.c:37][main]HOST_CMD:num 3,func 2
[02-12 17:56:03][HK_LOG][01_sys_cmd.c:38][main]SMART_HOST_CMD:num 3,func 2
[02-12 17:56:03][HK_LOG][01_sys_cmd.c:71][main]cmd number is invalid!!!
sumu@virtual-machine:~/6temp/test$ ./a.out 201
[02-12 17:56:08][HK_LOG][01_sys_cmd.c:37][main]HOST_CMD:num 3,func 2
[02-12 17:56:08][HK_LOG][01_sys_cmd.c:38][main]SMART_HOST_CMD:num 3,func 2
[02-12 17:56:08][HK_LOG][01_sys_cmd.c:118][SmartHostTest2]This is SmartHostTest2!!!
[02-12 17:56:08][HK_LOG][01_sys_cmd.c:119][SmartHostTest2]arg=2,*pParam=2,pBuf.a=200,pBuf.b=b
sumu@virtual-machine:~/6temp/test$ ./a.out 203
[02-12 17:56:10][HK_LOG][01_sys_cmd.c:37][main]HOST_CMD:num 3,func 2
[02-12 17:56:10][HK_LOG][01_sys_cmd.c:38][main]SMART_HOST_CMD:num 3,func 2
[02-12 17:56:10][HK_LOG][01_sys_cmd.c:71][main]cmd number is invalid!!!