打印

请教:如何高效处理不连续的函数指针,谢谢!

[复制链接]
3385|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
汽车电子|  楼主 | 2008-10-13 15:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  如下:


void    (CmdCls:: *CmdProcessTab[CMD_TOTAL_NUM])(uchar *p)= 
{   // 函数表
    ......
};


void      Function(void)
{
  void    (DownloadCmdCls::*pExecuteCmd)(uchar *p); // 定义函数指针

   ......
   pExecuteCmd = CmdProcessTab[CmdIndex];            
  (DCMD.*pExecuteCmd)(PSC);
   ......
}

///////////////////////
现在的问题: CmdIndex是双字节命令字,即0x0000~0xffff
但实际应用中不可能有65535个命令,中间很多空的,且不规则的。
有何好的办法 ??谢谢!

相关帖子

沙发
汽车电子|  楼主 | 2008-10-13 15:27 | 只看该作者

用switch又太多了,几百个处理

    也不想浪费很多空间来写满函数表......

使用特权

评论回复
板凳
HWM| | 2008-10-13 16:16 | 只看该作者

为何要这样玩?建议用hash

使用特权

评论回复
地板
| | 2008-10-14 09:06 | 只看该作者

为什么不定义成连续的呢?不连续是不是要不停的给函数指针

使用特权

评论回复
5
汽车电子|  楼主 | 2008-10-14 10:58 | 只看该作者

5楼兄弟,enum是数值,当然可以

   现在的命令表是字符串"T43"、"T60"等...,必须把字符串命令对应成数值命令,才可以直接索引。
   函数表和enum是不一样的,函数表是列出函数的入口地址,不连续的。

使用特权

评论回复
6
农民讲习所| | 2008-10-14 11:56 | 只看该作者

字符串命令必须先转换为可用索引的整数表达方式

使用特权

评论回复
7
xwj| | 2008-10-14 12:39 | 只看该作者

当然是查找表格啦

使用特权

评论回复
8
刘前辈| | 2008-10-14 14:03 | 只看该作者

函数指针数组的用法

函数指针最常见的用途之一是转换表(jump table)。转换表最好用个例子来解释,以下代码取自一个袖珍式计算器。程序已经从键盘上读入了两个数(op1和op2)和一个操作符oper。下面的代码对操作符进行测试,然后决定调用哪个函数:

switch (oper){     // 枚举变量oper
case ADD:   //  函数名字符串/枚举常量标识符  
         result = add( op1,op2 );
         break;
case SUB:
         result = sub( op1,op2 );
         break;
case MUL:
         result = mul( op1,op2 );
         break;
case DIV:
         result = div( op1,op2 );
         break;
......

对于一个新奇的具有上百个操作符的计算器,这条switch语句将会非常之长。

下面用转移表来化简这类应用。
double add ( double,double );
double sub ( double,double );
double mul ( double,double );
double div ( double,double );

创建函数指针数组
double (*oper_func[])(double,double) ={add,sub,mul,div,...};

应用:用下面这条语句替换前面整条switch语句:
result = oper_func[ oper ]( op1,op2 );

(上例中switch( oper )中的oper是一个枚举变量。)

使用特权

评论回复
9
李冬发| | 2008-10-15 00:40 | 只看该作者

建一张对照表

使用特权

评论回复
10
myfaith| | 2008-10-15 09:03 | 只看该作者

我在程序中也如11楼

但是当函数有的带参数有的不带参数时如何处理?

使用特权

评论回复
11
汽车电子|  楼主 | 2008-10-15 09:50 | 只看该作者

命令不多时常用的方法是:命令表 对应 函数表

////////////// 命令表
const  char   CmdTab[CMD_TOTAL_NUM][4] = 
{
   {"T43"},
   {"T60"},
   {"AAA"},
   {"AB"},
};

////////////// 命令表对应的函数表,必须一一对应,次序不能错。
void    (*CmdFuncTab[CMD_TOTAL_NUM])(uchar *p)=
{   
    T43_Function,
    T60_Function,
    AAA_Function,
    AA_Function,
};


////////////// 命令处理
void      CmdProcessFunction(void)
{
  void    (*pExecuteCmd)(void); // 定义函数指针

   ......
   CmdIndex = FindCmd();  // 查找字符串命令在命令表中的位置
   pExecuteCmd = CmdTab[CmdIndex];    // 
  (*pExecuteCmd)();                   // 执行命令
   ......
}

使用特权

评论回复
12
农民讲习所| | 2008-10-15 09:53 | 只看该作者

函数指针数组,用在LZ这种场合,不太好维护。

可以用消息处理代替。

使用特权

评论回复
13
汽车电子|  楼主 | 2008-10-15 10:04 | 只看该作者

如果数值命令是连续的

  只需要函数表,而无需命令表。
  
  不连续的整形数值命令和字符串命令,区别在于查找值,查找数值当然比查找字符串简单多了。


////////////// 命令表 (不连续的数值,从小到大排列,方便查找)
const  uint16   CmdTab[CMD_TOTAL_NUM] =
{
   0x0001,
   0x0002,
   0x0110,
   0x0130,
};

////////////// 命令表对应的函数表,必须一一对应,次序不能错。
void    (*CmdFuncTab[CMD_TOTAL_NUM])(uchar *p)=
{   
    Function1,
    Function2,
    Function3,
    Function4,
};


////////////// 命令处理
void      CmdProcessFunction(void)
{
  void    (*pExecuteCmd)(void); // 定义函数指针

   ......
   CmdIndex = FindCmd();  // 查找数值命令在命令表中的位置
   pExecuteCmd = CmdTab[CmdIndex];    //
  (*pExecuteCmd)();                   // 执行命令
   ......
}

使用特权

评论回复
14
computer00| | 2008-10-15 10:11 | 只看该作者

直接一个个字符串匹配吧……匹配了就调用函数……

使用特权

评论回复
15
汽车电子|  楼主 | 2008-10-15 10:13 | 只看该作者

请教15楼,农民讲习所,消息怎么处理?谢谢!

   现在是接收到一帧数据,根据其中包含的命令来处理这帧数据。
   命令值0x0000~0xffff,不连续,约有300多个
   要考虑到以后增加命令时,程序容易扩展。

使用特权

评论回复
16
农民讲习所| | 2008-10-15 10:27 | 只看该作者

消息处理:

首先谈谈用在这里的好处:
   兼容:上位机升级后,即使下位机不升级,原功能照常使用。这是消息处理自身的特性。
   分类处理:命令是分类的,比如0x10-0x23(TXX)的所有命令是一类,这类就可以用一个消息代替,消息可带参数,命令的下属参数XX。
   模块的集中类处理:switch只需处理几个到十几个命令。
   高度模块化:便于维护。这是消息处理特性。

处理方式:协议解析时,最好建立一个处理数据表,将代码转换为数据语言。
比如:
struct xxx
{
   unsigned int mCmdStart;
   unsigned int mCndEnd;
   unsigned int mMsg_Proc;
   ......
};
struct xxx sxxx[] = {
 { 0x10, 0x23, Msg_System, .... },
 ........
};

使用特权

评论回复
17
农民讲习所| | 2008-10-15 10:35 | 只看该作者

如果LZ代码都完成的话

也可以这样改进:
    将协议解析看作是一个低层的驱动程序,这样模块的处理函数是不能直接表达在协议解析模块中的,外部模块可以包含协议解析。在协议解析模块,使用函数指针注册方式,将函数处理指针传递给协议解析模块。这样避免协议解析中直接引用具体的函数。这样的函数指针处理,就是回调函数的处理方式了。
    回调函数不处理一个个的命令,而是修改为处理一类命令,类的一个个命令是回调函数内部再处理的。
   LS说的数据转换表还是需要的。

使用特权

评论回复
18
汽车电子|  楼主 | 2008-10-15 11:09 | 只看该作者

谢谢,代码未完成

使用特权

评论回复
19
victech| | 2008-10-17 00:45 | 只看该作者

听课

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

366

主题

2057

帖子

5

粉丝