打印
[C语言]

我的代码简史:楼主从单片机coder到嵌入式programer的简单历程

[复制链接]
楼主: keer_zu
手机看帖
扫描二维码
随时随地手机跟帖
81
keer_zu|  楼主 | 2014-5-22 17:16 | 只看该作者 回帖奖励 |倒序浏览
今天太忙了。没时间整理很多:

二. 监听套接字初始化

开始之前,先介绍一下这个程序最主要的几个数据结构:
/* 套接字结构 */
typedef struct Sockets {
        fd_set readfds, writefds, exceptfds; // 1. 要被检测的可读、可写、例外的套接字集合

        int PmuSock;                                // 2. PMU规范套接字
        ......
       
        struct Sockets_Comm *Comm;        // 3. 为设置中每一个通讯通道建立网络接口
} Sockets;

1. 做过IO复用的都知道这个。
2. 用来监听(listen())主站链接的监听socket。
3. 是个结构体数组:数组长度等于通信通道数量。结构体定义如下:

        /* COMM网络结构 */
        typedef struct Sockets_Comm{
                int Protocol;                // 1. 该链接使用的规约类型
                int MainSock;                // 2. 主套接字(即上面提到的监听套接字accept到的链接套接字)
                pthread_t MainThreadID; // 4. 主线程ID,该线程用于处理该链接通信。
                pthread_cond_t MainCond;
                pthread_mutex_t MainMutex;
               
                ............
        }Sockets_Comm;
        1. 规约类型:该链接使用哪种通信协议。
        2. (如上注释)
        3. (如上注释)

使用特权

评论回复
82
keer_zu|  楼主 | 2014-5-23 09:20 | 只看该作者
本帖最后由 keer_zu 于 2014-5-25 08:14 编辑

【插播】   ----知识点
开闭原则
在面向对象编程领域中,开闭原则规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”[1],这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。该特性在产品化的环境中是特别有价值的,在这种环境中,改变源代码需要代码审查,单元测试以及诸如此类的用以确保产品使用质量的过程。遵循这种原则的代码在扩展时并不发生改变,因此无需上述的过程。

开闭原则的命名被应用在两种方式上。这两种方式都使用了继承来解决明显的困境,但是它们的目的,技术以及结果是不同的。
梅耶开闭原则[编辑]
勃兰特·梅耶一般被认为是最早提出开闭原则这一术语的人,[来源请求]在他1988年发行的《面向对象软件构造》中给出。这一想法认为一旦完成,一个类的实现只应该因错误而修改,新的或者改变的特性应该通过新建不同的类实现。新建的类可以通过继承的方式来重用原类的代码。衍生的子类可以或不可以拥有和原类相同的接口。

梅耶的定义提倡实现继承。具体实现可以通过继承方式来重用,但是接口规格不必如此。已存在的实现对于修改是封闭的,但是新的实现不必实现原有的接口。

多态开闭原则[编辑]
在20世纪90年代,开闭原则被广泛的重新定义由于抽象化接口的使用,在这中间实现可以被改变,多种实现可以被创建,并且多态化的替换不同的实现。

相比梅耶的使用方式,多态开闭原则的定义倡导对抽象基类的继承。接口规约可以通过继承来重用,但是实现不必重用。已存在的接口对于修改是封闭的,并且新的实现必须,至少,实现那个接口。

罗伯特·C·马丁1996年发表的**《开闭原则》[2]是使用这种方法的启发式著作。在2001年,Craig Larman把开闭原则关联到了Alistair Cockburn的名为受护的变量的模式以及David Parnas关于信息隐藏的讨论。[3]



以上内容来源于《维基百科》,总得来说,开闭原则不仅针对面向对象设计,即使面向过程设计的软件,如果尽可能做到这一点也是很有必要的。虽然面向过程的先天性决定了,这是困难的。然而有些规模庞大的软件:如linux内核,虽然它本身具备面向对象思想,终究不是一个完全面向对象的大工程,但是它的开闭原则做得很到位,这个了解的人一定深有体会。

使用特权

评论回复
评分
参与人数 1威望 +6 收起 理由
dong_abc + 6 开闭原则
83
corset| | 2014-5-23 16:52 | 只看该作者
mark一下。

使用特权

评论回复
84
ytmpeigd| | 2014-5-26 20:39 | 只看该作者
mark 一下.

使用特权

评论回复
85
yao1318| | 2014-5-26 22:07 | 只看该作者
学习中

使用特权

评论回复
86
keer_zu|  楼主 | 2014-5-28 21:49 | 只看该作者
最近太忙,之前的东西整理起来也着实不易,编程无止境,改变是必须的。

使用特权

评论回复
评分
参与人数 1威望 +6 收起 理由
dong_abc + 6
87
bu2zhouzhu| | 2014-5-29 15:54 | 只看该作者
likezk 发表于 2014-5-17 09:35
  同样的感受啊,我的编程思路也是这么一步步升级过来的。从最初的全局变量满天飞,到后来的的功能划分, ...

请问参数传递具体是指什么?

使用特权

评论回复
88
tongluren| | 2014-5-29 16:07 | 只看该作者
mark,学习~~~

使用特权

评论回复
89
lh18753385| | 2014-6-5 17:50 | 只看该作者
mark

使用特权

评论回复
90
keer_zu|  楼主 | 2014-6-6 09:01 | 只看该作者
本帖最后由 keer_zu 于 2014-6-7 22:21 编辑

最近太忙,代码分析耽误了一阵子,恐怕一时半会儿还不能续上,最近一直在考虑一个问题:面向对象真的是最好的吗?真的完全适用于嵌入式开发吗?

      曾经看到过Linus在一个帖子里痛批了面向对象语言。他认为面向对象语言以对象为核心,加一些相关联的方法,简直是呓语。重要的东西应该是数据结构,对象本身有啥重要?真正有意思的,是在不同类型的不同对象交互而且有锁规则的时候。但是,即使是这时候,封装什么“对象接口”也绝对错误,因为不再是单一对象的问题了。他的结论是,面向对象解决的都是一些小问题。
确实有很多“大人物”一直强调:“最重要的是数据结构”。

       关于这个问题,我最近几天在考虑。一个基本的现象是:目前几乎所有的操作系统都不是以对象为核心的,就拿大家熟悉的ucos来说,它最核心的是:
           多任务的实现 --- systick中断中利用TCB(任务控制块)链表和任务状态信息(就绪、空闲、挂起等)完成对任务的调度。
           优先级的实现 --- 有一个专门的数据结构(优先级数组)来实现优先级。
           中断的管理 ------
           内存的管理 ------ 内存控制块
           任务间的通信和同步等 ------ 消息队列,互斥量,邮箱等
无不体现了数据结构的重要,这里面几乎看不到对象的存在。
到底对象的适用范围在哪里,我们该怎么做?其实这是一个很有挑战性的问题,目前还没有看到过专门讨论这个问题的论著。首先我们大致可以看到:所有“平台部分”代码(像操作系统)最好不要以对象为中心,在没有使用操作系统的应用里,对CPU的管理:中断的管理,并发的实现,消息和同步机制等也属于这个范畴,这部分的特点是:
           1. 所完成功能是对CPU功能的扩充和管理。
           2. 虽然CPU平台有差异,但是体系结构相同或相似,处理方法大部分相同(否则就不存在跨平台的OS)。
           3. 这部分是同CPU打交道的,和人类的思维差别很大。
所有业务相关的信息最好要以对象为中心。除了上述“平台部分”的代码,剩下应该都是业务(广义)上的内容,这部分的特点是:
           1. 所完成的功能是系统具体的业,不是平台的扩展和管理。
           2. 该部分和CPU无关,可以以对象为中心。
所以,关于这个问题可以给出以下结论:
        在软件领域,可以不用想物理学那样,需要考虑到理论的统一性,比如:宏观上用一套定理,量子尺度用另一套就会让人不舒服 --- 凭什么同样的宇宙给出不一样的描述方式?这也是爱因斯坦后半辈子想解决的问题。软件领域不受物理规律支配,能完成功能,解决问题就是王道。完全可以针对系统的不同实体部分采用不同的设计方法学。事实上我们一直都是这么做的,看看我们的个人电脑系统的操作系统部分和上面的应用软件。
       这样,我们的问题就变成:
            1. 在那些开发过程中需要做这样的划分(平台部分和应用部分)
            2. 怎么划分两部分的界线。
            3. 怎么才能最有效的结合两部分,有没有一套完整统一的方法。
            4. 两部分各自的实现问题。

其中第4个问题是我们千百本书里面介绍有的。要这样,最近一直在想这个问题:

使用特权

评论回复
91
laosizhender| | 2014-6-7 20:13 | 只看该作者
跟着LZ的脚步走

使用特权

评论回复
92
jerry7921| | 2014-6-8 15:22 | 只看该作者
写的太多了,指出关键思路就好啦

使用特权

评论回复
93
zuoxuqi| | 2014-6-8 21:31 | 只看该作者
楼主很牛,标记一下,回头接着听

使用特权

评论回复
94
keer_zu|  楼主 | 2014-6-13 09:41 | 只看该作者
转一断关于面向对象局限性的讨论,不错!

Soul:我在写书讨论“面向对象的局限性”
我 :En.这个倒与我的意见一致。哈哈哈。
我 :“绝对可以用面向过程的方法来实现任意复杂的系统。要知道,航天飞机也是在面向过程的时代上的天。但是,为了使一切变得不是那么复杂,还是出现了‘面向对象程序设计’的方法。”
我 :——哈,我那本书里,在“面向对象”一部分前的引文中。就是这样写的。
Soul:现在的程序是按照冯。诺伊曼的第一种方案做的,本来就是顺序的,而不是同步的。CPU怎么说都是一条指令一条指令执行的。
我 :面向过程是对“流程”、“结构”和“编程方法”的高度概括。而面向对象本身只解决了“结构”和“编程方法”的问题,而并没有对“流程”加以改造。
Soul:确实如此。确实如此。
我 :对流程进一步概括的,是“事件驱动”程序模型。而这个模型不是OO提出的,而是Windows的消息系统内置的。所以,现在很多人迷惑于“对象”和“事件”,试图通过OO来解决一切的想法原本就是很可笑的。
Soul:我先停下来,和你讨论这个问题,顺便补充到书里去。
我 :如果要了解事件驱动的本质,就应该追溯到Windows内核。这样就涉及到线程、进程和窗体消息系统这些与OO无关的内容。所以,整个RAD的编程模型是OO与OS一起构建的。现在很多的开发人员只知其OO的外表,而看不到OS的内核,所以也就总是难以提高。
Soul:OO里面我觉得事件的概念是很牵强的,因为真正的对象之间是相互作用,就好像作用力和反作用力,不会有个“顺序”的延时。
我 :应该留意到,整个的“事件”模型都是以“记录”和“消息”的方式来传递的。也就是说,事件模型停留在“面向过程”编程时代使用的“数据结构”的层面上。因此,也就不难明白,使用/不使用OO都能写Windows程序。
我 :因为流程还是在“面向过程”时代。
Soul:所以所谓的面向对象的事件还是“顺序”的。所以我们经常要考虑一个事件发生后对其他过程的影响,所以面向对象现在而言是牵强的。
我 :如果你深入OS来看SEH,来看Messages,就知道这些东西原本就不是为了“面向对象”而准备的。面向对象封装了这些,却无法改造它们的流程和内核。因为OO的抽象层面并不是这个。
我 :事件的连续性并不是某种编程方法或者程序逻辑结构所决定的。正如你前面所说的,那是CPU决定的事。
Soul:比如条件选择,其实也可以用一种对象来实现,而事实没有。这个是因为cpu的特性和面向对象太麻烦。
我 :可能,将CPU做成面向对象的可能还是比较难于想象和理解。所以MS才启动.NET Framework。我不认为.NET在面向对象方法上有什么超越,也不认为它的FCL库会有什么奇特的地方。——除了它们足够庞大。但是我认为,如果有一天OS也是用.NET Framework来编写的,OS一级的消息系统、异常机制、线程机制等等都是.NET的,都是面向对象的。那么,在这个基础上,将“事件驱动”并入OO层面的模型,才有可能。
Soul:所以我发觉面向对象的思维第一不可能彻底,第二只能用在总体分析层上。在很多时候,实质上我们只是把一个顺序的流程折叠成对象。
我 :倒也不是不可能彻底。有绝对OO的模型,这样的模型我见过。哈哈~~但说实在的,我觉得小应用用“绝对OO”的方式来编写,有失“应用”的本意。我们做东西只是要“用”,而不是研究它用的是什么模型。所以,“Hello World”也用OO方式实现,原本就只是出现在教科书中的Sample罢了。哈哈。
Soul:还有不可能用彻底的面向对象方法来表达世界。 因为这个世界不是面向对象的。 是关系网络图,面向对象只是树,只能片面的表达世界。所以很多时候面向对象去解决问题会非常痛苦。所以编程退到数据结构更合理,哈哈。
我 :如果内存是“层状存取”的,那么我们的“数据结构”就可以基于多层来形成“多层数据结构”体系。如果内存是“树状存取”的,那么我们当然可以用“树”的方式来存取。——可惜我们只有顺序存取的内存。
我 :程序=数据+算法 ——这个是面向过程时代的事。 程序=数据+算法+方法 ——在OO时代,我们看到了事件驱动和模型驱动,所以出现了“方法”问题。
Soul:我的经验是:总体结构->面向对象,关系->数据结构,实现->算法
Soul:看来我们对面向对象的认识还是比较一致的。

                                                   ------------  没有思辨就会堕落,就像没有监督就会腐败一样。




使用特权

评论回复
95
Zhou_g| | 2014-6-13 10:44 | 只看该作者
第一次能写到这样子很不错了,赞一个:)

使用特权

评论回复
96
keer_zu|  楼主 | 2014-6-16 18:12 | 只看该作者
       思绪如脱缰的野马,本来是想分析一下过去的代码,看看有什么发现没有。最后变成了“漫谈”,索性“发散思维”一把。
       一直在思考和实践嵌入式编程方面的问题,“前辈”们给出的忠告是:一定要“积累”,针对各种具体问题,大家分享了自己多年的经验,总结起来主要有一下内容:
    1. 编程技巧:可移植性问题、模块化,C语言问题等等。
    2. 功能实现:菜单的实现问题、GUI
    3. 工具的使用:keil,gcc,uml等。
    4. 外设驱动:显示屏,can,输入设备等。
    5. 功能模块:加密,校验,滤波等等。
    6. 处理器相关:中断处理技巧,寄存器操作,定时器等等。
其实,在我看来这个领域的不规范才是最大的问题,正如“抽象”是软件实践最有用的利器一样,只有积累没有总结和提炼便无法深入一样,因为事情是做不完的,这个行业涉及领域越来越多。而我们自己又往往把我们自己在mcu上面的工作特殊化和边缘化了:技巧的东西给过分夸大,平台被过分依赖,代码越来越有“个性”。。。。。 将mcu和大部分“通用处理器”(暂时这样称呼吧,其实除了PC部分长期被Intel的x86垄断很久意外,世界上有多少种CPU架构啊,他们都可以被称为“非通用”的)对立起来,然后说我是做“51”的,他是做“arm"的。
      其实我们做嵌入式遇到的上面大部分问题其实都是之前已经解决的问题,我们完全可以站在巨人的肩上,在这个基础上考虑更深层次的问题,只要别人已经解决过的问题,我们何不消化利用起来而自己从新总结呢?也不奇怪,我们的教科书中单片机就是讲一下cpu外设,汇编的基本操作,C语言给几个简单例子,仅此而已。工作中忙于应付老板的催促谁还有工夫去考虑,去学习,去借鉴,去整理? 站在巨人的肩上不是简单拿他的代码过来用用就算了,不是在论坛”跪求“某某问题紧急问题如何解决,得之而后就算了。要看这个问题解决了,是不是类似的问题都能这样做;我还能拿这样的方式去解决什么问题;这样做还有什么不足的地方,我该如何改进它等等。久而久之才能比别人做得更好,如果把创造性的想法加入进来,或许你也会创造奇迹。所谓规范化就是从开发过程的每个细节都先要吸收现成的,比较它已经被总结为”规范“,然后去改变和创造,用你的新“规范”去征服问题,征服别人。当一个需求摆正面前的时候,我们如何下手?如何分析问题,给出系统准确的定位,如何去设计规划,如何去实施,如何测试并改进。特殊需求如何满足?等等。
      所以说,规范才是根本的。上面5类问题其实前人都总结过很好的解决方法,一套行之有效的方法也有,我们何不拿过来用?

使用特权

评论回复
97
lantian5451| | 2014-6-17 12:01 | 只看该作者
记号

使用特权

评论回复
98
keer_zu|  楼主 | 2014-6-18 10:35 | 只看该作者
Zhou_g 发表于 2014-6-13 10:44
第一次能写到这样子很不错了,赞一个

代码分析暂停一下,后边有我的个人想法,可以看看。多提些意见哈

使用特权

评论回复
99
keer_zu|  楼主 | 2014-6-18 10:35 | 只看该作者
laosizhender 发表于 2014-6-7 20:13
跟着LZ的脚步走

代码分析暂停一下,后边有我的个人想法,可以看看。多提些意见哈

使用特权

评论回复
100
weihe123| | 2014-6-25 14:56 | 只看该作者
新手 看的有些头大

使用特权

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

本版积分规则