打印

一线研发之声:嵌入式C编程经验 之 函数指针

[复制链接]
14323|55
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
sedatefire|  楼主 | 2012-1-12 22:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/***********************************************************************************
* Filename: 一线研发之声:嵌入式C编程经验 之 函数指针
* Author:SedateFire
* E-mail:SedateFire@126.com
* Version:1.0
* Modify Date: 2012-01-12
* key: 嵌入式 函数指针 回调函数
* 本文首发: 环球资源-电子工程专辑-博客: 静心斋
***********************************************************************************/
      今天讨论什么呢,就讨论函数指针吧
       指针,在C语言中,是一个神圣的存在,可远观不可亵玩焉。函数指针,则是指针里面更让人敬畏的存在。
      如果你是一个单片机工作者,那么我猜测你八成忘记了函数指针如何定义,我几乎可以想象出你苦苦思索的神态了。
      如果你是一个linux底层驱动工作者,那么显然你要感叹造物住的神奇,函数指针竟是如此的遍地开花。尤其是linux 2.6以后的内核版本,你几乎要被指针晃花眼睛了,没有2年工作经验你都很难找到函数的原型定义在哪里。linux内核是一个高度抽象的世界,它把所有外设都视为文件,这一切,函数指针功不可没。
      前者太遥远,因为单片机基本上无法应用函数指针。比如Keil C51,函数指针是非常危险的,因为编译器不知道你这个指针要指向那个函数,也就无法分析分配每个局部变量。额...那个静态编译懂吗?用一句形象的话为君解惑,对于静态编译,每个变量(含局部)它的地址都是恒定不变的,但不是唯一的哦C51的栈,只用来存储函数返回地址。当然,特殊的递归编译不在讨论范围之内。所以,单片机程序和函数指针基本绝缘。只有一个途径可以用函数指针,那就是在编译阶段就告诉编译器这个函数指针的对象,且那个函数必须是有定义的,存在的。
     static const void (*function_pointer)(void) = function_exist;
     如果你的单片机程序中,有一个很大的很有规律的类似switch的写法,那么可以改写成静态函数指针数组,用查表方式,无论是可阅读性,还是程序效率,都颇有可道之处。如果不告诉编译器函数指针的对象,那你就完蛋了,程序也许能跑,但bug是莫名其妙的,没有任何逻辑的。如果你说那样干没有问题,那我也不争辩,只盼你能买几张彩票送我。



      linux当中的函数指针,那是锣鼓喧天鞭**齐鸣红旗招展人山人海啊~~。基本上只要是结构体,里面都必有一个函数指针,而且是一层嵌套一层地层层抽象上去,还有一堆令人头皮发麻的void *无类型指针,指针和变量齐飞,代码共数据一色。所以,高薪不是没有依据的。随着android的迅猛发展,大家接触linux内核的机会也会越来越多。



      当然多数人没那么好运的,我们说点实际点的,M0/M3平台。这个平台是很适用函数指针的,因为它是压栈式的编译方式。它最广泛的应用是回调函数,就我个人体会来讲,回调函数主要是为了分层清晰和模块化而存在的。我底层想传递消息给顶层,但又不好直接调用顶层函数,于是就用函数指针这种暗度陈仓的方式。有人说,直接调用不就得了,搞什么虚文。问题是顶层随时可能换,函数名也会变,到时候移植起来发现,顶层和底层盘根错节,相互依赖,那是很痛苦的。顶层对底层说,小兄弟,这个事情你先做,有什么情况你就打电话给我,剩下的我来处理。底层含着眼泪对顶层说,哥,你别说了,你还是先把电话号码给我吧,您干嘛老换号码啊。这个记录电话的媒介,就是回调函数指针。
          回调之妙,食髓知味。
夜了,闪人先,期待本文1.1版吧,呵呵

哎,自己回头看了一遍,内容冗余,表达转折突兀,不够圆润,容我再细细梳理一翻...

相关帖子

沙发
john_light| | 2012-1-12 22:57 | 只看该作者
顶后再看,广告位招租。

使用特权

评论回复
板凳
sedatefire|  楼主 | 2012-1-13 00:54 | 只看该作者
顶后再看,广告位招租。
john_light 发表于 2012-1-12 22:57


广告位招租? 哇靠,这也行
我挖井,你喝水啊...

使用特权

评论回复
地板
程序匠人| | 2012-1-13 01:12 | 只看该作者
前排抢位置!

使用特权

评论回复
5
chjmacong| | 2012-1-13 08:59 | 只看该作者
诸位大虾,这句话什么意思:

“我底层想传递消息给顶层,但又不好直接调用顶层函数,于是就用函数指针这种暗度陈仓的方式”

那我想问,既然顶层来回变,用函数指针又如何准确找到呢?

使用特权

评论回复
6
highgear| | 2012-1-13 10:56 | 只看该作者
顶。

C++ 下可以使用虚函数来实现通用及扩展接口,而 c 下面可以使用函数指针。函数指针在用 c 编写大中型软件中可以说必不可少。在编写底层模块时,一个原则就是必须假设不知道顶层情况,对于那些通用的公共模块,已经不是假设不知道,而是真的不知道。此时,回调函数的必要性会凸显出。在底层函数放置一个函数指针,把顶层的某个函数传递给函数指针后,底层模块才可以调用,而且可以调用不同的函数。这样既照顾了通用性,也不会牺牲特殊性。

例如:
FunctionPtr myCallback;

void Communication()
{
    ...
    if (done)      //底层通讯处理完毕,通知高层处理数据。这样可以保证底层的通用性
       if (myCallback != NULL) (*myCallback)();
}

使用特权

评论回复
7
zxcscm| | 2012-1-13 11:45 | 只看该作者
倾听研发之声

使用特权

评论回复
8
Andy_Meng| | 2012-1-13 11:49 | 只看该作者
期待本文1.1版

使用特权

评论回复
9
Cortex-M0| | 2012-1-13 18:47 | 只看该作者
写的真不错,顶~~~~

使用特权

评论回复
10
john_lee| | 2012-1-13 18:58 | 只看该作者
楼主的文风有趣,就像是“戏说.....”,写书吧。

使用特权

评论回复
11
Wayner| | 2012-1-13 19:47 | 只看该作者
写得好!很通俗易懂

使用特权

评论回复
12
江枫渔火| | 2012-1-13 20:42 | 只看该作者
KAO~
听君一席话,胜度十年书~
楼主加油写!

使用特权

评论回复
13
batsong| | 2012-1-13 22:00 | 只看该作者
懂的人能看懂,不懂的人看了楼主的内涵文更晕

使用特权

评论回复
14
linfuchi| | 2012-1-13 22:48 | 只看该作者
喜欢用函数指针的飘过

使用特权

评论回复
15
linfuchi| | 2012-1-13 22:51 | 只看该作者
13# batsong
**是写给能看的人看的:lol

使用特权

评论回复
16
sedatefire|  楼主 | 2012-1-13 23:19 | 只看该作者
急急如律令,聚!

使用特权

评论回复
17
sedatefire|  楼主 | 2012-1-13 23:36 | 只看该作者
本帖最后由 sedatefire 于 2012-1-18 23:50 编辑
诸位大虾,这句话什么意思:

“我底层想传递消息给顶层,但又不好直接调用顶层函数,于是就用函数指针这种暗度陈仓的方式”

那我想问,既然顶层来回变,用函数指针又如何准确找到呢? ...
chjmacong 发表于 2012-1-13 08:59



低层不能直接去调用顶层函数,这是铁则,记住。 不然就是系统越写越乱
在以后的工作经验中你会有体会的

使用特权

评论回复
18
caiwenbin| | 2012-1-16 22:12 | 只看该作者
同样喜欢用函数指针的飘过

使用特权

评论回复
19
caiwenbin| | 2012-1-16 22:20 | 只看该作者
个人感觉把每个文件中的全局变量和全局函数(指针的方式)封装在一个结构体内更好点!
以后使用方便!

使用特权

评论回复
20
sedatefire|  楼主 | 2012-1-18 23:49 | 只看该作者
本帖最后由 sedatefire 于 2012-1-18 23:50 编辑

急急如律令,再顶 :lol
最近正学着把公共代码,以库的方式模块化
感悟颇深
有的是何,学院派的理论,到了实践中是需要实事求是,与时俱进的
“低层不能直接去调用顶层函数,这是铁则,记住。” 在制作库的情况下,这句话我收回了,呵呵

使用特权

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

本版积分规则

4393

主题

5935

帖子

33

粉丝