搜索
bottom↓
回复: 114

困扰了我很久的问题,查了C语言的书始终找不到答案,是关于菜单函数的,希望高手能解答一

[复制链接]

出0入0汤圆

发表于 2009-2-23 21:16:14 | 显示全部楼层 |阅读模式
typedef struct{
        U8   KeyStateIndex; //当前状态索引号
        U8 KeyUpState; //按下"向上"键时转向的状态索引号
        U8 KeyDnState; //按下"向下"键时转向的状态索引号
        U8 KeyLState;  //按下"向左"键时转向的状态索引号
        U8 KeyRState;  //按下"向右"键时转向的状态索引号
        void (*CurrentOperate)(); //当前状态应该执行的功能操作
} KbdTabStruct;

U8就是uchar,结构体中可以定义成员变量,但是结构体里面的void (*CurrentOperate)();是什么意思呢?
知道的,请说下,我实在搞不清楚。

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。

出0入0汤圆

 楼主| 发表于 2009-2-23 21:17:28 | 显示全部楼层
下面是完整的程序
/******************************************************************************
* MenuFSM.C - 菜单框架和FSM代码
*

*
* DESCRIPTION: -
*
* modification history
* --------------------
* 01a, 04/sep/2007, 梁炎昌 written
* --------------------
******************************************************************************/

#include "CPU.H"
#include "KeyScan.H"
#include "KS0108.H"
#include "Menu.H"



//FIXME!
//改进想法:如何在菜单中可以接管其它有效按键,这里程序仅仅接管了方向按键,若能根据1--9这些数字按键跳转也是不错
//额外的问题是如何在应用程序中得到按键而却不需要在应用程序中做键盘检查循环(抢占CPU时间了,会使得原有可以在背景运行的程序无法执行)
/*
*   A>改进FSM编号的机制,使得维护更简单,能否自动编号?这样会使得添加FSM表容易
*   B>
*
*
*/
//-----------------------------------
//MenuTop.C
void DispMenuTop(void);
void DispMenuTopUp(void);
void DispMenuTopDown(void);
void DispMenuTopLeft(void);
void DispMenuTopRight(void);

void DispIcoMenuInit(void);
void DispIcoMenuUp(void);
void DispIcoMenuDown(void);
void DispIcoMenuLeft(void);
void DispIcoMenuRight(void);

//MenuFunc.C
void DispMenuFuncInit(void);
void DispMenuFuncUp(void);
void DispMenuFuncDown(void);
void DispMenuFuncLeft(void);
void DispMenuFuncRight(void);
//MenuPara.C
void DispMenuParaInit(void);
void DispMenuParaUp(void);
void DispMenuParaDown(void);
void DispMenuParaLeft(void);
void DispMenuParaRight(void);
//MenuLanguage.C
void DispMenuLanguageInit(void);
void DispMenuLanguageUp(void);
void DispMenuLanguageDown(void);
void DispMenuLanguageLeft(void);
void DispMenuLanguageRight(void);

//MenuMeasure.C
void DispMenuMeasureInit(void);
void DispMenuMeasureUp(void);
void DispMenuMeasureDown(void);
void DispMenuMeasureLeft(void);
void DispMenuMeasureRight(void);

#ifdef DynamicBar
//MenuFunc.C
void DispMenuDataInit(void);
void DispMenuDataUp(void);
void DispMenuDataDown(void);
void DispMenuDataLeft(void);
void DispMenuDataRight(void);
#endif
//-----------------------------------


void (*KeyFuncPtr)(); //按键功能指针

typedef struct{
        U8 KeyStateIndex; //当前状态索引号
        U8 KeyUpState; //按下"向上"键时转向的状态索引号
        U8 KeyDnState; //按下"向下"键时转向的状态索引号
        U8 KeyLState;  //按下"向左"键时转向的状态索引号
        U8 KeyRState;  //按下"向右"键时转向的状态索引号
        void (*CurrentOperate)(); //当前状态应该执行的功能操作
} KbdTabStruct;
//如下是菜单的关键代码
//不清楚具体含义 不能改动
//因为跟编译器相关
//如下的函数的名称也不可以轻易修改
/*
********************************************************************************
   FSM菜单实现机制说明:
A.一些约定:只有4个按键来做菜单周转,这四个按键Up/Down/Left/Down 对应功能是:确认/回退/向上/向下
B.每一层的bar型菜单需要大概5个状态(也就是5个函数)来实现,分别是MenuInit/MenuUp/MenuDown/MenuLeft/MenuRight
对应的功能解释:
MenuInit : 初始化菜单/重新初始化菜单,在进入一个子Bar菜单时,该函数把Bar显示指针根据语言指向子Bar的资源数组,
获得需要的参数:该子菜单多少个Bar项(ItemNum)/每个Bar项的字符长度(Size)/指向Bar显示内容的指针(DispItem).
而后,调用函数BarMenuInit,该函数初始化全部Bar显示--这就是初始化菜单.
若是是从子菜单返回时,那么在返回前,Pop函数被调用,各种菜单参数被还原,在进入本函数后,本函数根据得到参数显示Bar项
初始化菜单/重新初始化菜单的不同点在于:
初始化时      高亮显示的位置是在顶部,对应选中的Item也是在顶部
重新初始化时  由于用户通过按键向上/向下来选择Bar项,而后通过按键确认来进入子菜单,为了在退出子菜单时能得到跟进入
前一致的显示内容,因此需要备份一些相关数据:高亮的位置/选中的Item/当前FSM的Index号  在退出子菜单时Pop还原这些数据
本函数根据这些还原数据恢复显示.

MenuUp   : 根据Bar显示内容执行对应动作函数/或者周转到某层子菜单
MenuDown : 返回上层菜单 通常是简单调用Pop函数
MenuLeft : 移至上一个Bar项 通常是调用BarMenuLeft函数--该函数维护Bar的显示后FSM状态返回MenunInit,但由于没有打开Flash/Reflash项,因此没有执行MenuInit函数
MenuRight: 移至下一个Bar项 通常是调用BarMenuright函数--该函数维护Bar的显示后FSM状态返回MenunInit,但由于没有打开Flash/Reflash项,因此没有执行MenuInit函数


********************************************************************************
*/
_CONST_ KbdTabStruct KeyTab[]={
//       |-----------> Index
//       |  Up
//       |  |  Down
//       |  |  |  Left
//       |  |  |  |  Right   --->功能函数
//       |  |  |  |  |       |
       { 0, 1, 2, 3, 4,(*DispMenuTop)},// 待机画面
       { 1, 0, 0, 0, 0,(*DispMenuTopUp)},
       { 2, 0, 0, 0, 0,(*DispMenuTopDown)},
       { 3, 0, 0, 0, 0,(*DispMenuTopLeft)},
       { 4, 0, 0, 0, 0,(*DispMenuTopRight)},

       { 5, 6, 7, 8, 9,(*DispIcoMenuInit)}, //图标层菜单
       { 6, 0, 0, 0, 0,(*DispIcoMenuUp)},   //
       { 7, 0, 0, 0, 0,(*DispIcoMenuDown)}, //
       { 8, 0, 0, 0, 0,(*DispIcoMenuLeft)}, //
       { 9, 0, 0, 0, 0,(*DispIcoMenuRight)},//

       {10,11,12,13,14,(*DispMenuFuncInit)}, //"功能"
       {11, 0, 0, 0, 0,(*DispMenuFuncUp)},   //
       {12, 0, 0, 0, 0,(*DispMenuFuncDown)}, //
       {13, 0, 0, 0, 0,(*DispMenuFuncLeft)}, //
       {14, 0, 0, 0, 0,(*DispMenuFuncRight)},//

       {15,16,17,18,19,(*DispMenuParaInit)}, //"参数"
       {16, 0, 0, 0, 0,(*DispMenuParaUp)},   //
       {17, 0, 0, 0, 0,(*DispMenuParaDown)}, //
       {18, 0, 0, 0, 0,(*DispMenuParaLeft)}, //
       {19, 0, 0, 0, 0,(*DispMenuParaRight)},//

       {20,21,22,23,24,(*DispMenuLanguageInit)}, //"语言"
       {21, 0, 0, 0, 0,(*DispMenuLanguageUp)},   //
       {22, 0, 0, 0, 0,(*DispMenuLanguageDown)}, //
       {23, 0, 0, 0, 0,(*DispMenuLanguageLeft)}, //
       {24, 0, 0, 0, 0,(*DispMenuLanguageRight)},//


       {25,26,27,28,29,(*DispMenuMeasureInit)}, //"测量"
       {26, 0, 0, 0, 0,(*DispMenuMeasureUp)},   //
       {27, 0, 0, 0, 0,(*DispMenuMeasureDown)}, //
       {28, 0, 0, 0, 0,(*DispMenuMeasureLeft)}, //
       {29, 0, 0, 0, 0,(*DispMenuMeasureRight)},//
#ifdef DynamicBar
       {30,31,32,33,34,(*DispMenuDataInit)}, //"Data"
       {31, 0, 0, 0, 0,(*DispMenuDataUp)},   //
       {32, 0, 0, 0, 0,(*DispMenuDataDown)}, //
       {33, 0, 0, 0, 0,(*DispMenuDataLeft)}, //
       {34, 0, 0, 0, 0,(*DispMenuDataRight)},//
#endif

};

/*
*****************************************************************************
* CheckKey - 菜单键盘扫描函数
* DESCRIPTION: -
* 有有效按键则执行对应的功能函数
* 同时,若刷新标志有效,也执行相应的功能函数
* @Para void:
* Return :
*
*****************************************************************************
*/
U8 CheckKey(void)
{
    U8 IsKey;
    U8 Key;
    IsKey = 1;
    Key = KeyScan();
    switch(Key){
        case Key_Up:{ //向上键,找出新的菜单状态编号
            KeyFuncIndex=KeyTab[KeyFuncIndex].KeyUpState;
            KeyFuncPtr=KeyTab[KeyFuncIndex].CurrentOperate;
            (*KeyFuncPtr)();//执行当前按键的操作
            break;
        }
        case Key_Down:{ //向下键,找出新的菜单状态编号
            KeyFuncIndex=KeyTab[KeyFuncIndex].KeyDnState;
            KeyFuncPtr=KeyTab[KeyFuncIndex].CurrentOperate;
            (*KeyFuncPtr)();//执行当前按键的操作
            break;
        }
        case Key_Left:{ //向左键,找出新的菜单状态编号
            KeyFuncIndex=KeyTab[KeyFuncIndex].KeyLState;
            KeyFuncPtr=KeyTab[KeyFuncIndex].CurrentOperate;
            (*KeyFuncPtr)();//执行当前按键的操作
            break;
        }
        case Key_Right:{ //向右键,找出新的菜单状态编号
            KeyFuncIndex=KeyTab[KeyFuncIndex].KeyRState;
            KeyFuncPtr=KeyTab[KeyFuncIndex].CurrentOperate;
            (*KeyFuncPtr)();//执行当前按键的操作
            break;
        }
//---------------------------------------------------------------------------
#ifdef DigiKeyLink
/*
2006/09/08
数字键做快捷方式输入
1.判别数字键值是否小于ItemNum-1 否则是无效快捷方式
2.有效快捷方式下,把键值给Item,调用Key_Up的处理代码
3.需要添加超时处理,超时了就不能使用?(需要么?不需要么?)
*/
        case Key_1:
        case Key_2:
        case Key_3:
        case Key_4:
        case Key_5:
        case Key_6:
        case Key_7:
        case Key_8:
        case Key_9:
            Key = chang_code(Key);
            if((Key - '1') <= ItemNum-1){
                Item = Key - '1';
                if(ItemNum <= DispMax){//如果需要显示的项比可以显示的项少,那么修正Where 否则默认Where为0
                    Where = Item;
                }else{
                    Where = 0;
                }
                //-------------------------------------------------
                KeyFuncIndex=KeyTab[KeyFuncIndex].KeyUpState;
                KeyFuncPtr=KeyTab[KeyFuncIndex].CurrentOperate;
                (*KeyFuncPtr)();//执行当前按键的操作
                //-------------------------------------------------
            }else {
                IsKey = 0;
            }
            break;
#endif
//---------------------------------------------------------------------------
        default: //按键错误的处理
            IsKey = 0;
            break;
    }

    if(Flash){//两个当中有任意一个不为零,那么执行一次,我们应该不会出现Flash和ReFlash都是1的情况
        KeyFuncPtr=KeyTab[KeyFuncIndex].CurrentOperate;
        (*KeyFuncPtr)();//执行当前按键的操作
        Flash = 0;
       // ReFlash = 0;
     }

    return IsKey;
}

出0入0汤圆

发表于 2009-2-23 21:19:04 | 显示全部楼层
函数指针。

国内的C语言书都不咋地。
有本还算可以,《C pimer plus》。

出0入0汤圆

发表于 2009-2-23 21:44:46 | 显示全部楼层
同感
头像被屏蔽

出0入0汤圆

发表于 2009-2-23 23:47:19 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

发表于 2009-2-23 23:53:50 | 显示全部楼层
LS 讲解非常详细
令我茅塞顿开

出0入0汤圆

发表于 2009-2-24 10:41:06 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-2-24 12:06:58 | 显示全部楼层
留印

出50入0汤圆

发表于 2009-2-24 12:58:33 | 显示全部楼层
楼主可以参考下面的写法:

//定义菜单结构
struct menustruct                       
{
  uchar *menu_name;                     //菜单名字
  void (*menu_function) (viod);        //功能函数
};

typedef struct menustruct menu_struct;

#define MAIN_MENU_ITEMS 6               //主菜单条目数
menu_struct code main_menu[]=           //主菜单结构
{
        {"Add New Card",add_new_card},
        {"Delete Card",delete_card},
        {"Check Cards",check_cards},
        {"Check Records",check_records},
        {"Password Shift",password_shift},
        {"Time Set",time_set}
};

结构体第二项就是功能函数名字。

出0入8汤圆

发表于 2009-2-25 17:38:12 | 显示全部楼层
【4楼】 topdog解释的很详细

出0入0汤圆

 楼主| 发表于 2009-2-25 18:09:33 | 显示全部楼层
我知道那是一个指针函数

但是那个指针函数是写在结构体里的,这就是我不明白的地方了

结构体的成员,怎么能有指针函数呢,

我查了C语言的书,都找不到答案

是不是C不支持结构体里申明指针函数

出50入0汤圆

发表于 2009-2-25 18:34:35 | 显示全部楼层
指向函数的指针只是一个函数的起始地址,当然可以放到结构体里面

出0入0汤圆

发表于 2009-2-25 18:45:29 | 显示全部楼层
学习了!

出0入0汤圆

 楼主| 发表于 2009-2-25 19:16:18 | 显示全部楼层
cddyy 结构体定义的应该是一个指针的变量吧,指向函数的指针应该是一个常量,结构体中可以放常量的吗?


cddyy 你上面运行的那个是C程序吗,C程序允许这样使用结构体吗?

出0入0汤圆

 楼主| 发表于 2009-2-25 19:25:18 | 显示全部楼层
void (*CurrentOperate)();
刚刚想了想,这句话因该是定义一个指针,用来存放一个函数的首地址的
竟然是定义一个结构体变量的话,所以就能把他放在函数里是吧?

出0入0汤圆

发表于 2009-2-25 20:11:00 | 显示全部楼层
函数指针, 这个很有作用的啊!很多地方都能用到,这坛子里有人发过关于C指针的,里面有比较详细的介绍,楼主可以看看。
楼主贴的程序不错,最近在看这样的例子。感谢!

出0入0汤圆

发表于 2009-2-25 20:30:37 | 显示全部楼层
留印.

出0入0汤圆

发表于 2009-2-25 21:10:32 | 显示全部楼层
楼主注意区分函数指针和指针函数的区别。
结构体的成员,只能是变量,所以就可以是指针变量(其中就包括指向函数的指针变量);
结构体的成员,只能是变量,所以就不可以是函数(其中就包括返回指针的函数和需要指针作为参数的函数)。

出0入0汤圆

发表于 2009-2-25 22:22:52 | 显示全部楼层
【10楼】 zbh-avr
积分:13
派别:
等级:------
来自:
我知道那是一个指针函数

但是那个指针函数是写在结构体里的,这就是我不明白的地方了

结构体的成员,怎么能有指针函数呢,

我查了C语言的书,都找不到答案

是不是C不支持结构体里申明指针函数  

楼主请注意:
这个成员不是函数、而是指针,是个指向函数的指针,本质上是个变量、而不是函数声明/定义。

出0入0汤圆

发表于 2009-2-25 23:03:01 | 显示全部楼层
指针的领悟啊

出0入0汤圆

发表于 2009-2-25 23:08:38 | 显示全部楼层
函数指针  p_func   
    p_func();
等效与
    (*p_func)();

依次类推,有

    p_func();
等效与
    (*p_func)();
等效与
    (**p_func)();
等效与
    (***p_func)();
………………
………………
等效于
    (**************************************************************************************************************************p_func)();
等效于
………………
………………

出0入0汤圆

发表于 2009-2-25 23:47:39 | 显示全部楼层
正如二楼所说的
国内的C语言书都不咋地。
有本还算可以,《C pimer plus》。

《C pimer plus>>讲得还是蛮全的,老外写的.
程序设计还是买老外的经典书籍好

出0入0汤圆

 楼主| 发表于 2009-2-26 10:33:10 | 显示全部楼层
谢谢大家现在我明白了,但现在又有点新的问题,想请教一下大家

{ 0, 1, 2, 3, 4,(*DispMenuTop)},// 待机画面
       { 1, 0, 0, 0, 0,(*DispMenuTopUp)},
       { 2, 0, 0, 0, 0,(*DispMenuTopDown)},
       { 3, 0, 0, 0, 0,(*DispMenuTopLeft)},
       { 4, 0, 0, 0, 0,(*DispMenuTopRight)},

竟然最后一个结构体的成员是函数指针,那么就应该存放的是函数的首地址,函数的首地址应该是写函数名就可以了吧
但是这里的写的是(*DispMenuTopDown),我就不是很明白了,我觉的给结构体赋初值的话,应该写DispMenuTopDown函数名就可以了吧?
(*DispMenuTopDown)是什么意思呢?希望能得到回复
先谢谢了 ~

出0入0汤圆

发表于 2009-2-26 10:53:57 | 显示全部楼层
函数指针也只是个指针,和其它指针的区别就是指向的是个函数,里面保存的是函数的入口地址。函数指针变量不仅可以在结构体中定义,还可以定义为指针数组、指针链表、指针二叉树等等一切指针可以出现的地方。

出0入0汤圆

发表于 2009-2-26 11:07:11 | 显示全部楼层
【23楼】 zbh-avr
积分:14
派别:
等级:------
来自:
谢谢大家现在我明白了,但现在又有点新的问题,想请教一下大家

{ 0, 1, 2, 3, 4,(*DispMenuTop)},// 待机画面  
       { 1, 0, 0, 0, 0,(*DispMenuTopUp)},  
       { 2, 0, 0, 0, 0,(*DispMenuTopDown)},  
       { 3, 0, 0, 0, 0,(*DispMenuTopLeft)},  
       { 4, 0, 0, 0, 0,(*DispMenuTopRight)},  

竟然最后一个结构体的成员是函数指针,那么就应该存放的是函数的首地址,函数的首地址应该是写函数名就可以了吧
但是这里的写的是(*DispMenuTopDown),我就不是很明白了,我觉的给结构体赋初值的话,应该写DispMenuTopDown函数名就可以了吧?
(*DispMenuTopDown)是什么意思呢?希望能得到回复
先谢谢了 ~

楼主请参考21楼的回帖。
此处加“*”和“&”应该是一样的效果,而且不管加多少个,应该也是一样的效果。

出0入0汤圆

 楼主| 发表于 2009-2-26 12:09:26 | 显示全部楼层
【25楼】 eduhf_123 经历

我看了,21楼的,他说到的应该是函数的调用函数指针  
p_func     
    p_func();  
等效与
    (*p_func)();
但他和(*DispMenuTopRight)的形式是不一样的,前者后面有了个括号

刚刚参考了一下8楼的程序、

   menu_struct code main_menu[]=           //主菜单结构
{
        {"Add New Card",add_new_card},
        {"Delete Card",delete_card},
        {"Check Cards",check_cards},
        {"Check Records",check_records},
        {"Password Shift",password_shift},
        {"Time Set",time_set}
};

我也觉的应该这样子写,竟然是函数指针,那么给他赋初值的话,也就应该是函数的首地址既是函数名

但是对与给函数指针这样赋初值,我还是想不通。为什么可以这样子写呢(*DispMenuTopDown)?他和DispMenuTopDown是不是等价的呢?
如果等价的话又是为什么呢?

出0入0汤圆

 楼主| 发表于 2009-2-26 12:10:54 | 显示全部楼层
我还想问个问题
我用的是ICC的编译器,他是不是支持函数指针呢?
之前好象有听过,有些编译器是不支持函数指针的。

出0入0汤圆

发表于 2009-2-26 12:21:49 | 显示全部楼层
支持函数指针

出330入0汤圆

发表于 2009-2-26 12:42:46 | 显示全部楼层
(*DispMenuTopDown)?他和DispMenuTopDown是不是等价的呢?
=======================================
它们殊途同归。
    这纯粹编程书写的风格问题,C语言有个问题:写法灵活,但这反而令一些人无所适从。其实在感到困惑的地方,就大胆地改成自己想当然的写法,然后再对比一下实际运行效果是否有差异,或者编译通过不了,看下编译器是怎么提示的。

出0入0汤圆

发表于 2009-2-26 14:07:11 | 显示全部楼层
傻孩子的 指针都是纸老虎

出0入0汤圆

发表于 2009-2-26 14:13:23 | 显示全部楼层
学习了

出0入0汤圆

 楼主| 发表于 2009-2-26 15:47:21 | 显示全部楼层
是不是可以这样理解呢

*就是取指针所指向的变量内容,*函数名,也就是取出该函数的首地址,因为这样比较直观,所以就这样子写了。

要是有相应的资料看看就好了,我看的是潭浩强写的C语言,上面没提到这种写法

出0入0汤圆

发表于 2009-2-26 17:01:12 | 显示全部楼层
26楼,我是让你看21楼的那一长串星号,你只要理解了“有多少‘*’都一样”,就能理解你的代码里有没有“*”都一样、是“*”还是“&”也一样了。

出0入0汤圆

 楼主| 发表于 2009-2-26 17:14:15 | 显示全部楼层
【33楼】 eduhf_123 经历
我知道多少个星是一样的,但是21楼所讲的应该是用函数指针调用某个函数的时候的情况

定义了一个函数指针  p_func     
    p_func();  
等效与
        (*p_func)();
等效与  
        (**p_func)();
你上面说的有多少星都是样的,应该只是在函数调用情况

但是结构体里面 (*DispMenuTopDown),他应该等效与一个函数的首地址,你的意思是说在这个函数中(**DispMenuTopDown)也是可以的吗?

出330入0汤圆

发表于 2009-2-26 17:30:06 | 显示全部楼层
编译之后看一下汇编代码就清楚了,指针最终要转换成汇编的间接地址,而间接地址在汇编中只能穿一层“[ 马甲 ]”。

出0入0汤圆

 楼主| 发表于 2009-2-26 17:31:20 | 显示全部楼层
刚查了下书
在调用的时候 p_func(); 等价与 (*p_func)();也就是说函数名p_func和(*p_func)是等价的

(*p_func)和函数名等价
那么也就可以推出(*p_func)等价与(**p_func),依次类推也就是说(*************p_func)和p_func也是等价的
他们所表示的都是函数名p_func,也就是函数的首地址

eduhf_123 经历
你想要表达的是这个意思吗?

出0入0汤圆

发表于 2009-2-26 17:34:19 | 显示全部楼层
你只是知道有多少个“*”都一样,但是你并没有理解“为什么可以有多少个‘*’都一样呢?”。

  如果fun_name是一个函数名:那么对于代码中出现的fun_name,编译器是当成一个指针常量来对待的,它指向这个函数的入口地址(即该函数第一条语句在代码空间中的地址);而对于&fun_name这样的形式,编译器理解为用户(程序员)是想要通过这样的代码来得到该函数的地址,因此,这样的写法,最终的效果,实际上也是得到了函数的入口地址。
  现在得到第一个结论:fun_name和&fun_name是等效的,即fun_name = &fun_name。
  由于“*”和“&”对指针类型而言是互逆操作,在第一个结论中的等式两边同时加上“*”,得到第二个结论:*fun_name和fun_name是等效的,即*fun_name = fun_name。
  从以上两个结论出发递推,可得fun_name前面有任意个“*”或者任意个“&”都一样。

出0入0汤圆

 楼主| 发表于 2009-2-26 17:34:43 | 显示全部楼层
【35楼】 zcllom 星罗棋布
我明白你的意思
实际操作看两种方法,是否都能达到同一效果
但我还是想理论解释下

不过你前面说的一句话,发人深思~
这纯粹编程书写的风格问题,C语言有个问题:写法灵活,但这反而令一些人无所适从。

出0入0汤圆

 楼主| 发表于 2009-2-26 17:43:48 | 显示全部楼层
【37楼】 eduhf_123 经历
在请教你一个问题
funname是函数的首地址,那么*funname就是取该地址所指向的内容,在这里所指向的内容是什么呢?

出0入0汤圆

 楼主| 发表于 2009-2-26 17:55:04 | 显示全部楼层
谢谢 eduhf_123 经历
的耐心解答
收获了不少

出0入0汤圆

发表于 2009-2-26 17:58:09 | 显示全部楼层
学习了!

出0入0汤圆

发表于 2009-2-26 17:58:10 | 显示全部楼层
学习了!

出0入0汤圆

发表于 2009-2-26 21:15:31 | 显示全部楼层
funname始终是个常量,那么*funname就是取这个常量的值,也就是说和没*一个样,如果funname是个指针,*funname才是该地址所指向的内容。

出0入0汤圆

发表于 2009-2-26 21:22:14 | 显示全部楼层
我的写法和楼主贴的差不多

出0入0汤圆

发表于 2009-2-27 14:44:46 | 显示全部楼层
学习了!

出0入0汤圆

发表于 2009-2-27 14:46:57 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-3-29 19:44:22 | 显示全部楼层
菜单程序太常用了

出0入0汤圆

发表于 2009-3-29 21:21:53 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-3-30 11:29:31 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-4-13 13:30:58 | 显示全部楼层
*fun_name = fun_name
------------------------------------------------------------------------------------------------------------------
fun_name始终是个常量,那么*fun_name就是取这个常量的值,也就是说和没*一个样,如果fun_name是个指针,*fun_name才是该地址所指向的内容。
------------------------------------------------------------------------------------------------------------------
这里并不是因为fun_name是个常量而使得*fun_name = fun_name,而是*操作符会将数组和函数指示符转换为指针,这里因为fun_name是个函数指示符,*fun_name等价于*(&fun_name),所以*fun_name = fun_name

出0入0汤圆

发表于 2009-4-13 13:32:19 | 显示全部楼层
说白了,函数的指针就是一个指向函数起始地址的指针,对于单片机为32位。

出0入0汤圆

发表于 2009-4-13 14:08:41 | 显示全部楼层
to LS:
对于8位机,应该是8位的吧

出0入0汤圆

发表于 2009-4-13 18:36:07 | 显示全部楼层
翻C语言参考手册看到这样一句话:
由于函数指示符可以通过寻常转换规则转换为函数指针,所以极少需要对函数使用&操作符。

出0入0汤圆

发表于 2009-8-4 15:59:11 | 显示全部楼层
最近也在学习 “ 梁炎昌 ”的这个菜单范例,收获很多

出0入0汤圆

 楼主| 发表于 2009-8-10 00:19:16 | 显示全部楼层
是啊,我现在又把他的PDF给看了一遍。

出0入0汤圆

发表于 2009-8-10 08:39:16 | 显示全部楼层
记号

出0入0汤圆

发表于 2009-8-10 08:45:05 | 显示全部楼层
很实用的程序,留个脚印

出0入0汤圆

发表于 2009-8-10 08:54:22 | 显示全部楼层
谢谢, mark

出0入0汤圆

发表于 2009-8-10 09:15:02 | 显示全部楼层
MARK

出0入0汤圆

发表于 2009-8-12 10:27:55 | 显示全部楼层
MARK

出0入0汤圆

发表于 2009-8-23 20:31:44 | 显示全部楼层
标记

出0入0汤圆

发表于 2009-8-23 20:35:34 | 显示全部楼层
标记

出0入0汤圆

发表于 2009-8-23 20:49:39 | 显示全部楼层
函数指针这个东西谭老师的C语言也讲了的吧。

出0入0汤圆

发表于 2009-10-31 16:55:24 | 显示全部楼层
标记 下,好东西

出0入0汤圆

发表于 2009-10-31 19:17:31 | 显示全部楼层
常用

出0入0汤圆

发表于 2009-10-31 22:32:43 | 显示全部楼层
学习了!

出0入0汤圆

发表于 2009-11-1 15:19:02 | 显示全部楼层
mark 4楼讲得很好

出0入0汤圆

发表于 2009-11-24 13:21:18 | 显示全部楼层
不错,我也标记下

出0入0汤圆

发表于 2009-11-24 15:14:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-11-24 16:29:30 | 显示全部楼层
函数指针,但是尽量少用,当单片机资源紧张的时候你会发现,漫天的飞机

最古老的那本谭浩强的c语言书里面就有啊。。

出0入4汤圆

发表于 2009-11-28 20:22:38 | 显示全部楼层
函数指针如果可以象数据指针一样,通过+,-变量来调用函数才用意义,看了上面的例子,都是要指向函数名的,能不能给个例子,靠+,-变量来调用函数的

出0入0汤圆

发表于 2009-11-28 20:58:06 | 显示全部楼层
标记

出0入0汤圆

发表于 2009-11-28 22:49:34 | 显示全部楼层
标记

出0入0汤圆

发表于 2009-12-18 14:59:47 | 显示全部楼层
看过很多次这种结构,好像只能在界面的切换的时候很方便,但是要修改我里面的参数的时候这种结构就用不起来了
不知是我理解错了,还是结构的缺陷
望知情的兄弟告诉一声

出0入0汤圆

发表于 2009-12-18 18:43:19 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-18 20:10:26 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-18 20:22:29 | 显示全部楼层
一般函数指针设为回调函数,当底层有消息,如键盘,定时器,中断等,就调用上层的函数,这种结构在窗口,菜单,控件等编程中很常见,特别消费类电子,手机等

出0入0汤圆

发表于 2009-12-18 21:02:59 | 显示全部楼层
ok

出0入0汤圆

发表于 2010-5-3 22:17:15 | 显示全部楼层
mark!!

出0入0汤圆

发表于 2010-5-11 15:03:30 | 显示全部楼层
困扰我好久的函数指针问题,今天终于得到了解决!忠心感谢各位大侠的耐心讲解!

出0入0汤圆

发表于 2010-5-11 16:58:39 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-2-22 22:11:57 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-2-22 22:56:49 | 显示全部楼层
指针函数和函数指针是两个概念。楼上的有搞混的。
这个是借鉴C++的封装的思想,把函数和数据封装起来。

出0入0汤圆

发表于 2011-2-28 22:10:00 | 显示全部楼层
4楼 标记

出0入0汤圆

发表于 2011-3-21 21:45:57 | 显示全部楼层
学习了。。

出0入0汤圆

发表于 2011-3-31 22:13:38 | 显示全部楼层
谢谢,有点收获。

出0入0汤圆

发表于 2011-4-5 20:48:21 | 显示全部楼层
菜单,顶!

出0入0汤圆

发表于 2011-4-5 21:12:05 | 显示全部楼层
学习

出0入0汤圆

发表于 2011-4-13 16:36:18 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-10-27 00:41:52 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-10-30 01:11:39 | 显示全部楼层
Mark

出0入0汤圆

发表于 2011-11-3 16:56:43 | 显示全部楼层
找了好久才找到

出0入0汤圆

发表于 2011-12-23 22:44:21 | 显示全部楼层
谢楼主及各位大侠,仔仔细细地看完了帖子,收获颇多啊

出0入0汤圆

发表于 2011-12-24 14:18:10 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-1-8 16:40:07 | 显示全部楼层
KeyTab[KeyFuncIndex].KeyUpState;是什么意思啊 怎么KeyTab里面是二维数组都引用KeyUpState

出0入0汤圆

发表于 2012-1-8 16:44:16 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-21 23:49:34 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-10-20 23:35:07 | 显示全部楼层
mark!!!!!!!!!!!!!!!!!

出0入0汤圆

发表于 2012-12-29 17:43:15 | 显示全部楼层
好东西,学习了。

出0入0汤圆

发表于 2012-12-30 08:25:06 来自手机 | 显示全部楼层
嗯嗯,值得参考!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-9-28 06:24

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表