第一篇:Java系統(tǒng)程序員修煉之道
Java系統(tǒng)程序員修煉之道
——動力節(jié)點(diǎn)java 一:Java語言學(xué)習(xí)
對線程(thread),串行化,反射,網(wǎng)絡(luò)編程,JNI技術(shù),容器(Map,List, Iterator), 類加載器(ClassLoader),輸入輸出流,垃圾回收機(jī)制,有比較深入的了解,最起碼做過項(xiàng)目應(yīng)用。有過Java項(xiàng)目的性能優(yōu)化經(jīng)驗(yàn),最起碼掌握一種性能監(jiān)視工具的使用,熟悉JVM參數(shù),最起碼知道可以在JVM啟動時指定不同垃圾回收機(jī)制,以及不同垃圾回收機(jī)制之間的差別,熟悉JVM參數(shù)優(yōu)化。二:J2EE方面
最好知道JDBC規(guī)范是怎么回事情,面對Oracle數(shù)據(jù)庫如果告訴你JDBC驅(qū)動不能用了,你還知道有OCI驅(qū)動可以。掌握常見的SQL語句,熟悉JMS,JNDI等組件,掌握一套web開發(fā)模式,從前臺到后臺,有能力整合好這樣的框架。理解并掌握MVC思想,像SSH已經(jīng)實(shí)現(xiàn)了MVC的分層,幾乎不需要你自己再實(shí)現(xiàn),假設(shè)你開發(fā)一個簡單的Swing程序,你能MVC就說明你真的掌握了MVC的精髓。有能力在J2EE前端開發(fā)中構(gòu)建自己的MVC模式,知道什么是WEB2.0,知道什么是SOA,SaaS,SaaP等含義 三:理解并能合理運(yùn)用設(shè)計模式,UML建模
知道并理解設(shè)計模式中蘊(yùn)含的幾種基本原則如:里氏替換原則,開閉原則,合成復(fù)用原則,依賴倒置原則有很好的理解,并能舉例說明。對常用的設(shè)計模式如工廠模式,單例模式,觀察者模式,責(zé)任鏈模式,橋接模式等知道靈活運(yùn)用,明白什么是回調(diào)(Callback)。最后用一位高人話來總結(jié)設(shè)計模式,它是為了讓軟件更容易被別人讀懂,更容易維護(hù)而產(chǎn)生,設(shè)計模式本質(zhì)是程序員之間的交流,如果A用工廠模式設(shè)計一個模塊B來接替,A只要說該模塊是工廠模式實(shí)現(xiàn),B維護(hù)起來應(yīng)該容易得多,所以設(shè)計模式是關(guān)于交流,不關(guān)于代碼。切忌濫用設(shè)計模式。學(xué)會使用UML建模工具至少熟悉一種URL建模工具。四:注重用戶體驗(yàn),掌握KISS原則,知道歐卡姆剃刀原則
顧客就是上帝這個口號我們已經(jīng)喊了N年了,程序員的勞動成果最終也需要轉(zhuǎn)換為服務(wù)提供給客戶,用戶體驗(yàn)至關(guān)重要,常常看到的場景是功能實(shí)現(xiàn)了,軟件很難使用,程序員有個很充足的理由我不是美工,其實(shí)注重用戶體驗(yàn)跟美工八桿子也打不到一起,F(xiàn)oxMail的成功在很大程度是用戶體驗(yàn)的成功,友好,清晰的用戶提示,強(qiáng)的容錯與糾錯設(shè)計是獲得好的用戶體驗(yàn)的不二法門。傻瓜相機(jī)顧名思義傻子都會使用,這個就著名的KISS原則(Keep itsimple and stupid)意思是UI設(shè)計要簡單明了,傻子一看就知道怎么用,想想我們做出來的東西,對照說明書都不知道怎么用。另外一個就是最著名的例子IPhone手機(jī)外觀設(shè)計,是典型的歐卡姆剃刀設(shè)計原則來完成人機(jī)交互。五:自動測試與軟件配置管理(SCM)實(shí)現(xiàn)
知道什么是軟件配置管理,知道Hudson運(yùn)用該工具SCM,知道怎么獲取測試代碼覆蓋率,Java有效代碼行數(shù)(NCSS),完成firebug,JDepend等工具集成ant/maven。熟悉并注重在開發(fā)過程中使用JUnit單元測試,理解白盒測試規(guī)范。六:熟悉常見的網(wǎng)絡(luò)通信協(xié)議
對HTTP協(xié)議,知道POST, GET的區(qū)別是什么,閱讀過HTTP相關(guān)的RFC文檔。學(xué)會使用sniffer工具查看數(shù)據(jù)包,幫助查找與調(diào)試程序,知道TCP與UDP的區(qū)別,知道并理解E-Mail發(fā)送與接受的協(xié)議如SMTP,POP3,IMAP等協(xié)議,了解MIME與Base64編碼。知道組播是怎么回事情。
七:面向市場,永遠(yuǎn)對新技術(shù)保持渴望
計算機(jī)技術(shù)的發(fā)展日新月異,做為IT行業(yè)的軟件開發(fā)人員要不斷的給自己充電,更新自己的技術(shù)與時代保持同步,同時還要面向市場,華為總裁任正非說過-“華為的技術(shù)革新必須面向市場”,作為程序員同樣要有市場意識,很多人都后悔沒有在android剛出來的時候加以關(guān)注學(xué)習(xí)。那些很早關(guān)注android開發(fā)技術(shù)的很多程序員因此獲得豐厚回報。如今HTML5得到越來越多的瀏覽器廠家支持,你是否已經(jīng)跟上腳步,開始學(xué)習(xí)。八:保持謙虛,三人行必有我?guī)?/p>
喬幫主說他要保持初心,努力學(xué)習(xí),我等更應(yīng)該保持謙虛,IT技術(shù)發(fā)展日新月異,在你眼中不可能實(shí)現(xiàn)的技術(shù),也許別人早已經(jīng)有思路。保持謙虛就有機(jī)會吸取別人身上的長處,古人有云:滿招損,謙受益。一個得道的高人更是說出了”下下人,上上智”的禪語。永遠(yuǎn)不要拒絕幫助你周圍的人解決難題,解決難題是進(jìn)步最快途徑。不要放棄任何一次可以提升自己技術(shù)與能力的機(jī)會。
九:養(yǎng)成總結(jié)的習(xí)慣,不斷反思
上學(xué)的時候老師常讓寫小結(jié),也沒總結(jié)出來所以然,以至于工作以后再也不提這檔子事情,建議每個項(xiàng)目做完以后對自己都有個小結(jié),總結(jié)自己在項(xiàng)目里面學(xué)到了什么,反問自己能不能完成在不需要別人幫助的情況下自己完成這樣的系統(tǒng)搭建,是否熟悉與掌握項(xiàng)目中所用到的技術(shù),即使有些東西不是你負(fù)責(zé)完成的但是什么也不能阻擋一顆求知的心,總結(jié)要盡量詳細(xì)記錄你遇到那些難題是怎么一個一個的解決的,下次再遇到你是否可以很快解決或者避免這樣的問題。有總結(jié)才有提高,孔子曰:學(xué)而不思則罔,如果我們只是coding到吐血,不思考,不總結(jié)提高,永遠(yuǎn)不可能有能有本質(zhì)提高,秦相李斯有云:“泰山不讓土壤,故能成其大,河海不擇細(xì)流,故能就其深”,點(diǎn)滴積累不斷總結(jié)方能量變導(dǎo)致質(zhì)變。十:數(shù)學(xué)功底與算法知識 用任何編程語言開發(fā)應(yīng)用,都離不開核心算法支持,很多國外的軟件單單從UI上看,恐怕寫幾年程序的人都可以模仿,但是UI之下的那些真實(shí)深淺不一,相信不是你想模仿就可以模仿的,為什么我們越來越山寨,因?yàn)槲覀儧]有核心競爭力,對于程序員來說算法與數(shù)學(xué)顯然是他最重要的核心競爭力之一?!端惴▽?dǎo)論》,《編程珠璣》等書絕對值得讀十遍。微軟亞洲研究院視覺計算組負(fù)責(zé)人在一次演講中說到他們招人的標(biāo)準(zhǔn)是“三好學(xué)生– 數(shù)學(xué)好,編程好,態(tài)度好”??墒乾F(xiàn)實(shí)的普遍情況卻是-微機(jī)原理鬧危機(jī),匯編語言不會變,實(shí)變函數(shù)學(xué)十遍。計算機(jī)基礎(chǔ)知識被大家普遍忽視。從今天開始好好學(xué)習(xí)吧…… 十一:Java代碼反編譯與代碼保護(hù)
Java編譯產(chǎn)生字節(jié)碼,因而可以被輕松的逆向工程(反編譯),微軟的C#生產(chǎn)的DLL也一樣可以被輕松反編譯。正式由于這個原因產(chǎn)生了許多Java開源的代碼保護(hù)工具,而Proguar是其中佼佼者,已經(jīng)被google集成在android之中用于Java代碼保護(hù) 十二:努力成為某個行業(yè)或者領(lǐng)域骨干
面對漫長的職業(yè)生涯,要想不被淘汰,必須具備一招鮮吃遍天下的能力,選擇自己感興趣的方向,努力而深入的研究,計算機(jī)技術(shù)發(fā)展到今天已經(jīng)細(xì)分很細(xì),努力研究一種Java開源框架或者開源HTTP服務(wù)器源碼或者研究過網(wǎng)絡(luò)爬蟲源碼或者WEBKIT內(nèi)核,不愁沒有人要你。如果你是非常了解金融,企業(yè)ERP,證券,保險,移動應(yīng)用行業(yè)的應(yīng)用開發(fā)業(yè)務(wù)的人,一樣不用愁工作。這些知識不隨語言而改變,努力做一個有核心競爭力的Java程序員。十三:提高語言與書面表達(dá)能力,掌握基礎(chǔ)的項(xiàng)目管理知識
文檔與語言表達(dá)能力是最好的向外界展現(xiàn)自己能力的方式,很多程序員編程能力很高,表達(dá)能力一般,Linux能夠成功,除了歸功于網(wǎng)絡(luò)社區(qū)的力量之外,也得益于Linux作者本人給各大基金會寫信,宣傳推廣,試想如果沒有良好的書面語言表達(dá)能力,即使Linux系統(tǒng)再優(yōu)秀,卻無法被準(zhǔn)確表達(dá),失去各大基金會的支持,Linux還會像今天這么好的局面嘛。所以重視文檔,重視提升溝通與表達(dá)能力,才有可能成為Java系統(tǒng)程序員。掌握基本的2/8原則,學(xué)會將模塊細(xì)化分配給不同的人,預(yù)見并控制項(xiàng)目風(fēng)險,把握項(xiàng)目進(jìn)度,優(yōu)化流程,合理的時間管理,了解TDD,熟悉敏捷開發(fā)模式,常規(guī)軟件開發(fā)模式。
第二篇:Java程序員修煉之道
從2002開始接觸Java學(xué)會HelloWorld這么經(jīng)典的程序到如今不知不覺已經(jīng)十年啦,十年中
親耳聽到過不少大牛的演講,見到過項(xiàng)目中的神人在鍵盤上運(yùn)指如飛的編程速度,當(dāng)時就
被震撼了。當(dāng)編程越來越成體力活,我們還能有自己的思想,還能修煉為Java系統(tǒng)級別的
程序員嘛?學(xué)習(xí)與修煉以下知識與技能,幫你早日達(dá)成愿望。
一:Java語言學(xué)習(xí)
對線程(thread),串行化,反射,網(wǎng)絡(luò)編程,JNI技術(shù),容器(Map,List, Iterator), 類加載器
(ClassLoader),輸入輸出流,垃圾回收機(jī)制,有比較深入的了解,最起碼做過項(xiàng)目應(yīng)用。有
過Java項(xiàng)目的性能優(yōu)化經(jīng)驗(yàn),最起碼掌握一種性能監(jiān)視工具的使用,熟悉JVM參數(shù),最起
碼知道可以在JVM啟動時指定不同垃圾回收機(jī)制,以及不同垃圾回收機(jī)制之間的
差別,熟悉JVM參數(shù)優(yōu)化。
二:J2EE方面
最好知道JDBC規(guī)范是怎么回事情,面對Oracle數(shù)據(jù)庫如果告訴你JDBC驅(qū)動不能用了,你
還知道有OCI驅(qū)動可以。掌握常見的SQL語句,熟悉JMS,JNDI等組件,掌握一套web開
發(fā)模式,從前臺到后臺,有能力整合好這樣的框架。理解并掌握MVC思想,像SSH已經(jīng)實(shí)
現(xiàn)了MVC的分層,幾乎不需要你自己再實(shí)現(xiàn),假設(shè)你開發(fā)一個簡單的Swing程序,你能MVC
就說明你真的掌握了MVC的精髓。有能力在J2EE前端開發(fā)中構(gòu)建自己的MVC模式,知道
什么是WEB2.0,知道什么是SOA,SaaS,SaaP等含義
三:理解并能合理運(yùn)用設(shè)計模式,UML建模
知道并理解設(shè)計模式中蘊(yùn)含的幾種基本原則如:里氏替換原則,開閉原則,合成復(fù)用原則,依賴倒置原則有很好的理解,并能舉例說明。對常用的設(shè)計模式如工廠模式,單例模式,觀
察者模式,責(zé)任鏈模式,橋接模式等知道靈活運(yùn)用,明白什么是回調(diào)(Callback)。最后用一位
高人話來總結(jié)設(shè)計模式,它是為了讓軟件更容易被別人讀懂,更容易維護(hù)而產(chǎn)生,設(shè)計模
式本質(zhì)是程序員之間的交流,如果A用工廠模式設(shè)計一個模塊B來接替,A只要說該模塊是
工廠模式實(shí)現(xiàn),B維護(hù)起來應(yīng)該容易得多,所以設(shè)計模式是關(guān)于交流,不關(guān)于代碼。切忌濫
用設(shè)計模式。學(xué)會使用UML建模工具至少熟悉一種URL建模工具。
四:注重用戶體驗(yàn),掌握KISS原則,知道歐卡姆剃刀原則
顧客就是上帝這個口號我們已經(jīng)喊了N年了,程序員的勞動成果最終也需要轉(zhuǎn)換為服務(wù)提
供給客戶,用戶體驗(yàn)至關(guān)重要,常常看到的場景是功能實(shí)現(xiàn)了,軟件很難使用,程序員有個
很充足的理由我不是美工,其實(shí)注重用戶體驗(yàn)跟美工八桿子也打不到一起,F(xiàn)oxMail的成功
在很大程度是用戶體驗(yàn)的成功,友好,清晰的用戶提示,強(qiáng)的容錯與糾錯設(shè)計是獲得好的
用戶體驗(yàn)的不二法門。傻瓜相機(jī)顧名思義傻子都會使用,這個就著名的KISS原則(Keep it
simple and stupid)意思是UI設(shè)計要簡單明了,傻子一看就知道怎么用,想想我們做出來的
東西,對照說明書都不知道怎么用。另外一個就是最著名的例子IPhone手機(jī)外觀設(shè)計,是 典型的歐卡姆剃刀設(shè)計原則來完成人機(jī)交互。
五:自動測試與軟件配置管理(SCM)實(shí)現(xiàn)
知道什么是軟件配置管理,知道Hudson微機(jī)原理鬧危機(jī),匯編語言不會變,實(shí)變函數(shù)學(xué)
十遍。計算機(jī)基礎(chǔ)知識被大家普遍忽視。從今天開始好好學(xué)習(xí)吧……
十一:Java代碼反編譯與代碼保護(hù)
Java編譯產(chǎn)生字節(jié)碼,因而可以被輕松的逆向工程(反編譯),微軟的C#生產(chǎn)的DLL也一樣可
以被輕松反編譯。正式由于這個原因產(chǎn)生了許多Java開源的代碼保護(hù)工具,而Proguard是
其中佼佼者,已經(jīng)被google集成在android之中用于Java代碼保護(hù),訪問這里了解更多:
http://proguard.sourceforge.net/
十二:努力成為某個行業(yè)或者領(lǐng)域骨干
面對漫長的職業(yè)生涯,要想不被淘汰,必須具備一招鮮吃遍天下的能力,選擇自己感興趣的
方向,努力而深入的研究,計算機(jī)技術(shù)發(fā)展到今天已經(jīng)細(xì)分很細(xì),努力研究一種Java開源
框架或者開源HTTP服務(wù)器源碼或者研究過網(wǎng)絡(luò)爬蟲源碼或者WEBKIT內(nèi)核,不愁沒有人要
你。如果你是非常了解金融,企業(yè)ERP,證券,保險,移動應(yīng)用行業(yè)的應(yīng)用開發(fā)業(yè)務(wù)的人,一樣不用愁工作。這些知識不隨語言而改變,努力做一個有核心競爭力的Java程序員。
十三:提高語言與書面表達(dá)能力,掌握基礎(chǔ)的項(xiàng)目管理知識
文檔與語言表達(dá)能力是最好的向外界展現(xiàn)自己能力的方式,很多程序員編程能力很高,表達(dá)
能力一般,Linux能夠成功,除了歸功于網(wǎng)絡(luò)社區(qū)的力量之外,也得益于Linux作者本人給各
大基金會寫信,宣傳推廣,試想如果沒有良好的書面語言表達(dá)能力,即使Linux系統(tǒng)再優(yōu)秀,卻無法被準(zhǔn)確表達(dá),失去各大基金會的支持,Linux還會像今天這么好的局面嘛。所以重視
文檔,重視提升溝通與表達(dá)能力,才有可能成為Java系統(tǒng)程序員。掌握基本的2/8原則,學(xué)
會將模塊細(xì)化分配給不同的人,預(yù)見并控制項(xiàng)目風(fēng)險,把握項(xiàng)目進(jìn)度,優(yōu)化流程,合理的時
間管理,了解TDD,熟悉敏捷開發(fā)模式,常規(guī)軟件開發(fā)模式。
十四:掌握英語,良好的讀寫能力
英語是計算機(jī)的母語,掌握好英語對于閱讀英文資料學(xué)習(xí)新技術(shù)大有幫助,我的建議是盡量
讀英文原版書,如果是算法方面的可能會困難一點(diǎn),但是其它像設(shè)計模式,軟件工程,OO
編程思想等盡量讀原版,提高自己的英文水平,多多訪問開發(fā)者,code project,程序員天堂,Pc-magazine等英文IT網(wǎng)站。英語絕對是你必須修煉與提高的技能。此外英語好在外資企業(yè)
尤其重要,只有外語足夠好才可能在外資企業(yè)中突破職業(yè)瓶頸,向上發(fā)展。
第三篇:Java程序員修煉十大過程
Java程序員修煉十大過程
學(xué)習(xí)java這么久,見到過項(xiàng)目中的神人在鍵盤上運(yùn)指如飛的編程速度,當(dāng)時就被震撼了。當(dāng)編程越來越成體力活,我們還能有自己的思想,還能修煉為Java系統(tǒng)級別的程序員嘛?學(xué)習(xí)與修煉以下知識與技能,幫你早日達(dá)成愿望。
一、努力成為某個行業(yè)或者領(lǐng)域骨干
面對漫長的職業(yè)生涯,要想不被淘汰,必須具備一招鮮吃遍天下的能力,選擇自己感興趣的方向,努力而深入的研究,計算機(jī)技術(shù)發(fā)展到今天已經(jīng)細(xì)分很細(xì),努力研究一種Java開源框架或者開源HTTP服務(wù)器源碼或者研究過網(wǎng)絡(luò)爬蟲源碼或者WEBKIT內(nèi)核,不愁沒有人要你。如果你是非常了解金融,企業(yè)ERP,證券,保險,移動應(yīng)用行業(yè)的應(yīng)用開發(fā)業(yè)務(wù)的人,一樣不用愁工作。這些知識不隨語言而改變,努力做一個有核心競爭力的Java程序員。
二、保持謙虛,三人行必有我?guī)?/p>
喬幫主說他要保持初心,努力學(xué)習(xí),我等更應(yīng)該保持謙虛,IT技術(shù)發(fā)展日新月異,在你眼中不可能實(shí)現(xiàn)的技術(shù),也許別人早已經(jīng)有思路。保持謙虛就有機(jī)會吸取別人身上的長處,古人有云:滿招損,謙受益。一個得道的高人更是說出了“下下人,上上智”的禪語。永遠(yuǎn)不要拒絕幫助你周圍的人解決難題,解決難題是進(jìn)步最快途徑。不要放棄任何一次可以提升自己技術(shù)與能力的機(jī)會。
三、熟悉常見的網(wǎng)絡(luò)通信協(xié)議
對HTTP協(xié)議,知道POST, GET的區(qū)別是什么,閱讀過HTTP相關(guān)的RFC文檔。學(xué)會使用sniffer工具查看數(shù)據(jù)包,幫助查找與調(diào)試程序,知道TCP與UDP的區(qū)別,知道并理解E-Mail發(fā)送與接受的協(xié)議如SMTP,POP3,IMAP等協(xié)議,了解MIME與Base64編碼。知道組播是怎么回事情。
四、理解并能合理運(yùn)用設(shè)計模式,UML建模
知道并理解設(shè)計模式中蘊(yùn)含的幾種基本原則如:里氏替換原則,開閉原則,合成復(fù)用原則,依賴倒置原則有很好的理解,并能舉例說明。對常用的設(shè)計模式如工廠模式,單例模式,觀察者模式,責(zé)任鏈模式,橋接模式等知道靈活運(yùn)用,明白什么是回調(diào)(Callback)。最后用一位高人話來總結(jié)設(shè)計模式,它是為了讓軟件更容易被別人讀懂,更容易維護(hù)而產(chǎn)生,設(shè)計模式本質(zhì)是程序員之間的交流,如果A用工廠模式設(shè)計一個模塊B來接替,A只要說該模塊是工廠模式實(shí)現(xiàn),B維護(hù)起來應(yīng)該容易得多,所以設(shè)計模式是關(guān)于交流,不關(guān)于代碼。切忌濫用設(shè)計模式。學(xué)會使用UML建模工具至少熟悉一種URL建模工具。
五、自動測試與軟件配置管理(SCM)實(shí)現(xiàn)
知道什么是軟件配置管理,知道Hudson-http://java.net/projects/hudson/運(yùn)用該工具SCM,知道怎么獲取測試代碼覆蓋率,Java有效代碼行數(shù)(NCSS),完成firebug,JDepend等工具集成ant/maven.熟悉并注重在開發(fā)過程中使用JUnit單元測試,理解白盒測試規(guī)范。
六、Java語言學(xué)習(xí)
對線程(thread),串行化,反射,網(wǎng)絡(luò)編程,JNI技術(shù),容器(Map,List, Iterator),類加載器(ClassLoader),輸入輸出流,垃圾回收機(jī)制,有比較深入的了解,最起碼做過項(xiàng)目應(yīng)用。有過Java項(xiàng)目的性能優(yōu)化經(jīng)驗(yàn),最起碼掌握一種性能監(jiān)視工具的使用,熟悉JVM參數(shù),最起碼知道可以在JVM啟動時指定不同垃圾回收機(jī)制,以及不同垃圾回收機(jī)制之間的差別,熟悉JVM參數(shù)優(yōu)化。
七、掌握英語,良好的讀寫能力
英語是計算機(jī)的母語,掌握好英語對于閱讀英文資料學(xué)習(xí)新技術(shù)大有幫助,我的建議是盡量讀英
文原版書,如果是算法方面的可能會困難一點(diǎn),但是其它像設(shè)計模式,軟件工程,OO編程思想等盡量讀原版,提高自己的英文水平,多多訪問開發(fā)者,code project,程序員天堂,Pc-magazine等英文IT網(wǎng)站。英語絕對是你必須修煉與提高的技能。此外英語好在外資企業(yè)尤其重要,只有外語足夠好才可能在外資企業(yè)中突破職業(yè)瓶頸,向上發(fā)展。
八、養(yǎng)成總結(jié)的習(xí)慣,不斷反思
上學(xué)的時候老師常讓寫小結(jié),也沒總結(jié)出來所以然,以至于工作以后再也不提這檔子事情,建議每個項(xiàng)目做完以后對自己都有個小結(jié),總結(jié)自己在項(xiàng)目里面學(xué)到了什么,反問自己能不能完成在不需要別人幫助的情況下自己完成這樣的系統(tǒng)搭建,是否熟悉與掌握項(xiàng)目中所用到的技術(shù),即使有些東西不是你負(fù)責(zé)完成的但是什么也不能阻擋一顆求知的心,總結(jié)要盡量詳細(xì)記錄你遇到那些難題是怎么一個一個的解決的,下次再遇到你是否可以很快解決或者避免這樣的問題。有總結(jié)才有提高,孔子曰:學(xué)而不思則罔,如果我們只是coding到吐血,不思考,不總結(jié)提高,永遠(yuǎn)不可能有能有本質(zhì)提高,秦相李斯有云:“泰山不讓土壤,故能成其大,河海不擇細(xì)流,故能就其深”,點(diǎn)滴積累不斷總結(jié)方能量變導(dǎo)致質(zhì)變。
九、Java代碼反編譯與代碼保護(hù)
Java編譯產(chǎn)生字節(jié)碼,因而可以被輕松的逆向工程(反編譯),微軟的C#生產(chǎn)的DLL也一樣可以被輕松反編譯。正式由于這個原因產(chǎn)生了許多Java開源的代碼保護(hù)工具,而Proguard是其中佼佼者,已經(jīng)被google集成在android之中用于Java代碼保護(hù)。
十、面向市場,永遠(yuǎn)對新技術(shù)保持渴望
計算機(jī)技術(shù)的發(fā)展日新月異,做為IT行業(yè)的軟件開發(fā)人員要不斷的給自己充電,更新自己的技術(shù)與時代保持同步,同時還要面向市場,華為總裁任正非說過-“華為的技術(shù)革新必須面向市場”,作為程序員同樣要有市場意識,很多人都后悔沒有在android剛出來的時候加以關(guān)注學(xué)習(xí)。那些很早關(guān)注android開發(fā)技術(shù)的很多程序員因此獲得豐厚回報。如今HTML5得到越來越多的瀏覽器廠家
支持,你是否已經(jīng)跟上腳步,開始學(xué)習(xí)。
第四篇:程序員修煉 收藏
程序員修煉 收藏
程序就是一系列按步驟進(jìn)行的操作序列,它有好多種級別,比如最低級的微程序、次低級的匯編程序、高級的各種編程語言程序、最高級的腳本語言程序,也許我列的不對,但沒關(guān)系,我要說的是不管是那個級別的程序,其本質(zhì)都是操作的邏輯序列。大多數(shù)系統(tǒng)和應(yīng)用程序都是建立在高級編程語言上的,比如C、C++、C#、FORTRAN、BISIC、JAVA等等,就讓我們只關(guān)注這一級的編程能力吧。因此如果一個程序員的邏輯能力不高,他永遠(yuǎn)都不能成為一名具有合格職業(yè)水準(zhǔn)的程序員,我們在下面的討論有關(guān)編程能力的方方面面,最終都是為了最大程度地提高和實(shí)現(xiàn)一名程序員的邏輯能力。
一、掌握基礎(chǔ)知識:十六年寒窗的持續(xù)積累
從7歲讀小學(xué)起,經(jīng)過16年的學(xué)習(xí),你從軟件專業(yè)本科畢業(yè)后,必須完成以下幾門專業(yè)課程的學(xué)習(xí):計算機(jī)組成、操作系統(tǒng)原理、匯編語言、數(shù)據(jù)結(jié)構(gòu)、編譯原理、數(shù)據(jù)庫原理、軟件工程、結(jié)構(gòu)性設(shè)計語言(PASCAL、C)、面向?qū)ο笤O(shè)計語言(C++、C#)、計算機(jī)網(wǎng)絡(luò)等,你最好還懂一些算法分析、分布式系統(tǒng)、計算機(jī)圖形學(xué)、形式邏輯、人工智能原理、軟件設(shè)計模式、軟件構(gòu)架/框架等研究生的課程,16年來,你積累的除了知識,更重要的是形成最適合自己的學(xué)習(xí)方法和工作方法。這些是你具備程序員職業(yè)水準(zhǔn)的基礎(chǔ)能力,不要受什么計算機(jī)軟件怪杰之類傳奇的影響,那不過是小概率事件,而且這些怪杰們就算沒有讀過軟件本科和研究生,也往往自學(xué)了大多數(shù)專業(yè)課程,很可能比在校學(xué)習(xí)的學(xué)生對這些課程的精髓部分理解的更好,還有他們的工作方法和思維方式是特別而高效的,但普遍性差,可以借鑒,不宜模仿。好,所以現(xiàn)在你只需要問問自己,那些課程和知識都學(xué)會并掌握了嗎?如果是,那就準(zhǔn)備好進(jìn)行實(shí)踐了。
二、在實(shí)踐中提高:成為一名高水平的Coder
好了,你畢業(yè)了,在校功課都不錯,也找了一個專業(yè)對口的工作,你想大展鴻圖了,可是別急,你的翅膀還不夠硬,不信我們說來看看。
通常,你在工作中都會用到某一種單位/公司固定的操作系統(tǒng)和編程語言開發(fā)環(huán)境,比如Windows、UNIX、LINUX等操作系統(tǒng),又比如用VC、VB、PB、Delph、JAVA、Motif/XWindow、QT、OpenGL、OpenInventor等編程語言和開發(fā)環(huán)境,我們在后面把它們合稱為開發(fā)環(huán)境。就在校學(xué)習(xí)的有關(guān)開發(fā)環(huán)境的知識而言,大概你距工作需要的差距是不小的,當(dāng)某個操作系統(tǒng)和編程語言環(huán)境成為你的飯碗時,就不應(yīng)也不能用通過課程/認(rèn)證考試之類的眼光和要求來評價你的能力,即使你能考100分。你需要深入地學(xué)習(xí)該操作系統(tǒng)和編程語言環(huán)境的各類開發(fā)手冊的所有內(nèi)容,你會說大多數(shù)你都用不上,其實(shí)你既對又不對,對的是單從使用的角度而言,你確實(shí)用不上開發(fā)手冊的大多數(shù)內(nèi)容,比如龐大的VC開發(fā)類庫和復(fù)雜的開發(fā)環(huán)境,你在實(shí)際工作中能用到的不到總數(shù)的1/10或1/5,不對的地方在于,你用到的部分不是孤立存在的,它們是整個體系中的一部分,只有對整個體系有了一個較完整的了解,才能得心應(yīng)手、隨心所欲地用好你用到的部分,你才算初步具備在這種開發(fā)環(huán)境下進(jìn)行Coding的職業(yè)水準(zhǔn)(還遠(yuǎn)不夠程序員的職業(yè)水準(zhǔn)呢),而這只是剛開始。如何才能真正掌握一種開發(fā)環(huán)境的全面的知識呢,最原始的辦法就是讀開發(fā)指南/教程、參考手冊,一般來講,學(xué)習(xí)開發(fā)指南/教程時,你如果是一個認(rèn)真的人,都會完成5/10~7/10左右內(nèi)容的學(xué)習(xí)和練習(xí),如果你想成為職業(yè)選手,就應(yīng)該完成9/10以上內(nèi)容的學(xué)習(xí)和練習(xí)。參考手冊不同,大多數(shù)所謂的“程序員”們只是用到了才翻翻,這差的太遠(yuǎn)了,你應(yīng)該象讀開發(fā)指南/教程一樣,每個環(huán)節(jié)都要讀,比如VC,參考手冊中的每個類,類的每個函數(shù),都要讀上幾遍,它們往往是一小伙一小伙地糾纏在一起使用的,開始時讀得你毫無頭緒、心煩意亂,不要緊,還有一手呢,如果你開發(fā)環(huán)境安裝的全面,它們往往都有開發(fā)商做的demo例子可看,你就進(jìn)入另一個境界了,開始時你關(guān)注demo中的具體技術(shù),后來你發(fā)現(xiàn)這些demo的程序?qū)懙亩歼€算不錯,結(jié)構(gòu)簡單但合理,如果你真的用心,就一定能發(fā)現(xiàn)一些個別的demo是極品,它所展現(xiàn)的程序邏輯結(jié)構(gòu)是你設(shè)計不出來的,你現(xiàn)在有點(diǎn)更關(guān)心它的程序設(shè)計構(gòu)架,甚于對你原始目的(某種相關(guān)的技術(shù)/技巧)的關(guān)注,這時的你,開始了從一名Coder向一名Programmer的轉(zhuǎn)變,你會忍不住要看看開發(fā)商提供的源程序,比如.h和.cpp,通常你會找到include路徑下所有的.h程序,你才知道,哇!好多好多東東在參考手冊中都沒提到,你要學(xué)的太多了,沒時間顧及其它的業(yè)余愛好了,現(xiàn)在知道為什么程序員是年輕人的職業(yè)了吧,你要有足夠多的時間才行,即使你的智商有160。如果你走到這一步,在你工作的團(tuán)隊中,已經(jīng)是經(jīng)常有人向你請教技術(shù)問題,經(jīng)常有人請求你幫忙debug,你已是公認(rèn)的“高手”了,別得意,因?yàn)槟闳匀皇莻€Coder,為什么這么說呢,你想想,你已深入了解了這個開發(fā)環(huán)境中的各種技能,知道一名Coder如何用好這些東西,可是你能設(shè)計的出提供給Coder們用的東西嗎?唔??,你想了想,可能還不太行。對了,就是這樣,你還是一名小我境界的程序員呢,本質(zhì)是個Coder,當(dāng)然已是一名高水平的Coder了,然而你需要進(jìn)一步登堂入室才能成為一名真正的程序員。
讓我們繼續(xù)吧,通常你都是從精通一種編程環(huán)境開始的,假設(shè)你已經(jīng)較為精通在Windows下用VC開發(fā)軟件了,這時在技術(shù)和技巧方面你將面臨一小一大兩個挑戰(zhàn),第一個小挑戰(zhàn)是如果公司/單位改換了開發(fā)環(huán)境,比如用LINUX下的QT交互語言工具進(jìn)行開發(fā),你不過是把前面掌握VC的過程再來一遍,由于在主觀上經(jīng)歷了VC工具的學(xué)習(xí)過程,在客觀上各種開發(fā)環(huán)境都有太多相似的方面,這回你掌握的應(yīng)該較快。要小心,在這時第一次誘惑之門打開了,因?yàn)槟愀杏X良好,看!這回這么快,我就這么好地掌握了新的開發(fā)環(huán)境,你開始關(guān)注其它暫時還用不到的同類環(huán)境,比如VB、Delph、JAVA,如饑似渴地掌握各種開發(fā)工具,證明自己的學(xué)習(xí)能力和價值,但你忘了一點(diǎn),你仍然是個Coder,只不過是一個在好多開發(fā)環(huán)境下都能編程的Coder,就像你生活在中國,因而精通了漢語,工作需要你又掌握了英語,然后你就來了勁,把俄語、日語、阿拉伯語、拉丁語,等等等等,都學(xué)習(xí)個遍,我只能說,有點(diǎn)BT。你忘了自己是個職業(yè)人,同一類的東西工作中用得到才需學(xué)習(xí),太多太多的Coder們喜歡在一起比較和炫耀自己會掌握了幾種開發(fā)工具,不信你看看招聘時的求職書就知道了,sigh!他們中絕大多數(shù)人永遠(yuǎn)都只能停留在這個層次上,心浮氣躁,一生都再也當(dāng)不成真正的程序員了??偨Y(jié)一下,其實(shí)你在這時需要的是對自己掌握新開發(fā)環(huán)境的能力的自信,而不是一遍遍地重復(fù)來證明自己。第二個大挑戰(zhàn)就是你明白了只掌握VC是不夠的,你發(fā)現(xiàn)自己有點(diǎn)淺薄,有很多東東你會用但你不太懂,很多方面支持VC編程的知識你都沒掌握,比如操作系統(tǒng)的源碼、網(wǎng)絡(luò)協(xié)議知識、Windows 的注冊表、進(jìn)程和線程的基礎(chǔ)知識、硬件驅(qū)動方面的知識、ActiveX、Windows 龐大的 API,又是一個等等等等,這些基礎(chǔ)知識的學(xué)習(xí)和掌握可是要花費(fèi)大量時間的,你再一次深切地感到時間太不夠用了,因?yàn)檫@時的你大概有許多俗務(wù)纏身了,所以有點(diǎn)沮喪,還不用提IT業(yè)每天不知有多少新東西在發(fā)布,KAO,永遠(yuǎn)都跟不上,越拉越遠(yuǎn)了。哎!別氣餒,振作一點(diǎn),你還是忘記了自己是個職業(yè)人,既然好多東東在工作中你永遠(yuǎn)都沒機(jī)會用,那么干嘛要學(xué)呢?用什么才學(xué)什么,最多預(yù)測到馬上要用什么,先一步學(xué)什么好了,要知道沒有人是真正的、無所不精的全科大夫,除非你是神,但如果你還在耐著性子看這篇文章,你肯定是個人嘛。
OK,一般工作后三五年,你經(jīng)歷了上述過程,經(jīng)受了誘惑和考驗(yàn),終于明白了一個道理:你要的是強(qiáng)勁的學(xué)習(xí)知識的能力,是對某種軟件知識/技能的有深度的精通,一種摸到它的根的深度,而不是已掌握的技能的種類和數(shù)量。這時無論誰用他掌握了多少種你不會的技能來嚇唬你都沒用,你對他的層次只有蔑視。通過幾年的學(xué)習(xí)和工作,要記住最重要的一點(diǎn),永遠(yuǎn)最重要:對自己學(xué)習(xí)IT知識能力的自信,一個程序員一生都要不停地進(jìn)行高強(qiáng)度的學(xué)習(xí),用心問問自己,有沒有這個自信?別用虛榮心來騙自己哦,如果沒有的話,那就不必花費(fèi)你寶貴的時間向下看了,作者在此感謝你有耐心看到這里,現(xiàn)在建議你關(guān)閉這篇文章,趁著年輕,當(dāng)機(jī)立斷轉(zhuǎn)行吧!
三、注重邏輯:成為一名職業(yè)程序員
好,再前進(jìn)一點(diǎn)點(diǎn),你就要成為一名職業(yè)程序員了,讓我們繼續(xù)來完成這個任務(wù)吧!我們在前一節(jié)提到過,“你發(fā)現(xiàn)一些個別的demo是極品,它所展現(xiàn)的程序邏輯結(jié)構(gòu)是你設(shè)計不出來的,你現(xiàn)在有點(diǎn)更關(guān)心它的程序設(shè)計構(gòu)架,甚于對你原始目的(某種相關(guān)的技術(shù)/技巧)的關(guān)注”,其實(shí)你是在關(guān)注這個demo程序作者的思維邏輯,所有程序的本質(zhì)就是邏輯。技術(shù)你已經(jīng)較好地掌握了,但只有完成邏輯能力的提高,你才能成為一名職業(yè)程序員。打一個比方吧,你會十八般武藝,刀槍棍棒都很精通,但就是力氣不夠,所以永遠(yuǎn)都上不了戰(zhàn)場,這個力氣對程序員而言就是邏輯能力(其本質(zhì)是一個人的數(shù)學(xué)修養(yǎng),注意,不是數(shù)學(xué)知識)。邏輯能力也是逐步提高的,開始時你一定是用直觀的邏輯能力來編程的,怎么想就怎么編,不對就再改,在改進(jìn)中提高自己的邏輯能力,從直觀邏輯能力提高到抽象邏輯能力,這是很正常的。提前說一句吧,到達(dá)邏輯能力的至高境界,其表現(xiàn)是用數(shù)學(xué)語言來描述問題和問題的解決辦法,高度抽象!好,說回來吧,你要提高邏輯能力,最快的辦法就是讀別人寫的結(jié)構(gòu)優(yōu)秀的程序。優(yōu)秀的代碼是百讀不厭的(這句話是我抄來的),暫時放放對其中某種技術(shù)和技巧的關(guān)注吧,你要推導(dǎo)和學(xué)習(xí)的是這些好程序的邏輯結(jié)構(gòu),它們是被精心設(shè)計出來的。你可以先捂住這個demo程序,自己設(shè)計一個功能相同的程序結(jié)構(gòu),然后比較一下demo的程序結(jié)構(gòu),如果差距較大,那你就不應(yīng)簡單地改進(jìn)一下,而是要把demo作者設(shè)計的過程在心里復(fù)原一遍,做到這一點(diǎn)也許有點(diǎn)困難,但這種事干的多了,你就會越干越快,越來越得心應(yīng)手,你的邏輯能力飛速提升,你能看得上的邏輯結(jié)構(gòu)優(yōu)秀的程序開始不多了,下一步就是練習(xí)。從工作中開始吧,如果你有空閑,你需要做至少兩類練習(xí),一類是算法練習(xí),所有的經(jīng)典算法都是經(jīng)典的邏輯,題目有的是,像個好學(xué)生一樣吧,每年的國內(nèi)國際編程競賽都有邏輯要求非常高的題,你可以只選一兩道難題來做做。當(dāng)你可以把復(fù)雜的單遞歸程序(只有A調(diào)A)變成非遞歸程序時,已經(jīng)不錯了,如果你能看得懂雙遞歸程序(A調(diào)A、A調(diào)B、B調(diào)A、B調(diào)B都有),我為你鼓掌!你不必往下看了,我有點(diǎn)不好意思啦――班門弄斧,你快滾蛋吧!另一類是把以前和當(dāng)前你工作中你不滿意的程序推倒重新設(shè)計一遍,這非常重要,省時省力,因?yàn)槟闶煜ば枨?,技術(shù)上也沒問題,目的就是改進(jìn)程序的邏輯結(jié)構(gòu),很劃算哦,唯一要克服的就是:你對推翻以前工作中那點(diǎn)小小成就的心理障礙,如果你真想優(yōu)秀,說句粗話:這點(diǎn)心理障礙算個屁,一遍遍反復(fù)地推倒已有的成果只能使自己快速進(jìn)步,放手干吧,沒什么好可惜的,馬恩早就在《共.產(chǎn).黨宣言》里說過了:在這個過程中,你失去的只有鎖鏈(禁錮你思想的鎖鏈)。
讓我們來總結(jié)一下,經(jīng)過自我否定后,再生的你盡管對過去的“業(yè)績”還有一些眷戀,但已是一個初步具備職業(yè)水準(zhǔn)的程序員了,掌握了相應(yīng)的技術(shù)和技巧,具備了較高的抽象邏輯思維能力,最主要的特征是:能自覺地自我否定,不斷地追求更高水平的邏輯能力。
在這個過程中,如果你能注意以下一些小的方面,你前進(jìn)的步伐也許會快一些。
l 從編譯原理的角度來理解你工作中使用的高級語言,如果你做到這一點(diǎn),至少有兩個好處,第一個好處是避免一大堆低水平重復(fù)出現(xiàn)的編譯錯誤。一名優(yōu)秀的Coder平均在一個工作日中應(yīng)該完成200行以上的源碼,其編譯錯誤應(yīng)該控制在5個以下,要知道這200行源碼不是一次完成的,所以大多數(shù)情況下你都要追求一次編譯通過,而一名職業(yè)水準(zhǔn)的程序員,應(yīng)該進(jìn)一步做到即使用purify這類的工具來檢查源碼,也不會存在嚴(yán)重的內(nèi)存泄露。第二個好處是可以提高源碼的可讀性和效率。規(guī)范地編寫你的代碼使你自己的邏輯清晰,因?yàn)槟忝靼锥嗉訋讉€括號和空行、多換行對齊、多注釋,編譯器是會自動識別的,不影響程序執(zhí)行的效率,反過來,控制好遞歸調(diào)用和循環(huán)內(nèi)的if語句才是提高程序效率的關(guān)鍵,要全力避免遞歸,但要深刻理解遞歸,能通過自己建立堆棧來把遞歸程序轉(zhuǎn)換成非遞歸程序,要求還是較高的哦!
l 避免思維陷阱,只要你是人就一定有自己的思維慣性,這一定又會表現(xiàn)在你的程序邏輯中,有時你就是從這個慣性中跳不出來(誰都有這個時候),但要心里有數(shù)才行,所以你需要幫助,如果你有幾個水平相若或更高的職業(yè)伙伴,太好了,當(dāng)遇到花30分鐘還打不下的bug時,就別浪費(fèi)時間了,找他們吧,最要緊的是能思路清晰明確地表述你的問題,通常你自己在這個過程中或者伙伴中就有人把問題解決了,又快又好。另外,有幾個可以良性競爭的職業(yè)伙伴是人生的一件幸事,1+1>2,大家各有所長,你最好做到及時公開你的成果,技不壓身嘛,IT發(fā)展的這么快,你再優(yōu)秀,那點(diǎn)東東也沒有什么值得隱藏的,所以你可以技術(shù)或水平不夠高,但千萬不可以讓真正具有職業(yè)水準(zhǔn)的選手鄙視你的職業(yè)品質(zhì)和行為。
l 有自己debug的特點(diǎn),下面的說法作者不敢太肯定,只是經(jīng)驗(yàn)之談。即使在VC這種高度完善的開放環(huán)境下,你仍然應(yīng)該要求自己僅憑打印語句就能debug。這也有兩點(diǎn)好處,第一個好處是,遇到bug你會認(rèn)真想問題所在,而不是用debug工具一步步簡單地追蹤卡在哪兒了,你定位bug范圍的方式是從大到小、從粗到精,這是一種自頂向下的思維方式,而用工具追蹤,容易形成自底向上的思維方式,這不算好,你應(yīng)該先看到森林,再看到樹木。我反復(fù)提及:程序就是邏輯過程,大多數(shù)程序從main函數(shù)開始,是由數(shù)據(jù)結(jié)構(gòu)和功能子程序組成的一個樹形結(jié)構(gòu)的邏輯過程(要認(rèn)清即使是面向?qū)ο蟮某绦蛘Z言也是一樣的),它的執(zhí)行過程是深度優(yōu)先的,但你定位bug應(yīng)該是廣度優(yōu)先的,好好想想這一點(diǎn),嗯?第二個好處是強(qiáng)迫你思考并記住而不是用工具看到調(diào)用過程,你大腦的抽象邏輯思維能力和胳膊上肌肉的力量一樣,都是練出來的,如果你的bug是程序結(jié)構(gòu)上的邏輯錯誤引起的,這一點(diǎn)就非常重要了,順便說一句,最難打的bug就是程序邏輯結(jié)構(gòu)錯誤導(dǎo)致的bug。你要是真正明明白白地認(rèn)識到這兒了,那我就沒什么東西可以告訴你了。總之,程序員的職業(yè)水準(zhǔn):生產(chǎn)效率和程序質(zhì)量,主要是取決于源碼中bug的數(shù)量和debug的速度,而不是取決于編寫源碼的速度。給你一個我自己定義的考查一個職業(yè)程序員的指標(biāo):一個合格水準(zhǔn)的職業(yè)程序員,編程的時間如果算一份的話,其累計debug的時間不能超過一份,真正職業(yè)高手累計debug的時間應(yīng)該控制在0.5份以下,如何?你關(guān)上門悄悄問問自己,你花費(fèi)在編程和debug上的時間比例是多少?如果你把程序員作為自己一生的職業(yè),那么就永遠(yuǎn)都要牢記一點(diǎn):追求做一個0 bug的優(yōu)秀程序員!這是任何一個想成為職業(yè)程序員的人的理想,請相信:堅忍不拔地追求實(shí)現(xiàn)這個理想將讓你出類拔萃!
l 做好程序的單元測試,這是另一項(xiàng)考查你是否是一名具有合格職業(yè)水準(zhǔn)的程序員的一個必要指標(biāo)。其實(shí)在你拿到需求的時候就要準(zhǔn)備單元測試用例了,并且這些用例將直接影響你的詳細(xì)設(shè)計(有關(guān)軟件設(shè)計本來是該放在第四節(jié)講的)。我們還是打比方吧,當(dāng)你拿到一個需求時,除了分析它靜態(tài)的功能外,還應(yīng)明確它動態(tài)的操作/執(zhí)行過程,把這個動態(tài)過程明確地用流程圖畫出來,比如分為A~Z的26步,其中A又可以進(jìn)一步分解為A1~A5的5步,直到不能再分解為止。又比如說A3步不可分解了,那么你應(yīng)該把A3步的正常操作和所有五花八門的異常操作都列出來,確保正常的操作肯定正確,異常的操作起碼程序不退出才行。這樣你就要寫好多好多的測試用例,說句老實(shí)話,我也從來不寫!但我一般會列一個提綱,比如A3步有正常的操作a、b、c、d、e共5項(xiàng),異常的操作有f、g、h、i、j、k、l、m、n共9項(xiàng),你在進(jìn)行單元測試時都應(yīng)該跑一遍,這樣的程序都還不敢說質(zhì)量如何好,但起碼可以說較穩(wěn)定吧!如果要想在進(jìn)行單元測試時干得快、效率高,那么在進(jìn)行詳細(xì)設(shè)計時,你就應(yīng)該把A3步中對所有正常操作和異常操作的判斷都設(shè)計好,在編程實(shí)現(xiàn)A3步時,使得程序的結(jié)構(gòu)合理高效,對不對?所以,如果你在工作中是割裂地看待軟件工程中從需求、分析、設(shè)計、編程、測試等各個環(huán)節(jié),恐怕水平很有限喔!但如果你在分析需求時就能看到測試的問題,并改進(jìn)設(shè)計和實(shí)現(xiàn),為此做好相應(yīng)的準(zhǔn)備工作,嘿嘿,整個軟件開發(fā)過程你的效率會高很多,通常你在一個開發(fā)團(tuán)隊中就會高度自信的,你已越過當(dāng)一名偏頗、露骨的高手的境界,成為一個平靜的高手,這可是The best in the best!,用周星星的話說:是高手之高高手,因?yàn)閯e人看不出你高在哪兒,沒見你有什么高招或特拚命干,但反正你就是干得又快又好、又省力。關(guān)于進(jìn)行單元測試還有很多復(fù)雜的方法,在此本文只提到了最基本的一點(diǎn),目的是讓你在工作上考慮周全、安排有序,其它的自己琢磨吧,沒有人能替你吃飽飯!
l 如果你是用C++編程,我再簡單談?wù)動嘘P(guān)內(nèi)層釋放的一個小技巧,就是對所有你編寫的類,在構(gòu)造和析構(gòu)函數(shù)中加打印語句,統(tǒng)計每個類在運(yùn)行程序時構(gòu)造和析構(gòu)的地方,如果是配對的,那么起碼沒有對象類一級的內(nèi)層在程序運(yùn)行結(jié)束時沒有釋放,然后你就可以把打印語句刪掉了,招數(shù)雖土,但管用!
l 還有其它一些好習(xí)慣,在這里我隨筆寫一些,你要是有不同看法也請一笑過之吧。編程時應(yīng)該對齊縮進(jìn),一個縮進(jìn)用一個tab鍵,一般是4個空格,嚴(yán)格遵守開發(fā)團(tuán)隊的編程規(guī)范也是非常重要的。一個子程序不應(yīng)超過30行(不算空行),其內(nèi)多重循環(huán)不應(yīng)超過3層,否則都應(yīng)該分裂成兩個子程序,個別算法程序可以長一些,但也不宜超過200行。通常一個類的所有成員函數(shù)總和不宜超過1500行,多了就應(yīng)該考慮分解成兩個類(這個工作最好在設(shè)計時就完成)。每完成一小段程序,比如15~30行,就立即編譯運(yùn)行,不要假裝高手,先敲它一大堆程序,再編譯運(yùn)行,妄想一次成功,體驗(yàn)一種假爽的、虛榮的快感,或炫耀給別人看,這么做只能證明自己是一個不折不扣的傻瓜,裝酷而已。因?yàn)橹灰幸淮尾怀晒?,你就會花費(fèi)大量的時間來調(diào)程序,別人的進(jìn)度在這時就遠(yuǎn)遠(yuǎn)地超過你了,平常心是道,還是修煉真功夫吧!孫子兵法里關(guān)于這一點(diǎn)有明確的闡述,我就不引用了,但建議你真的不要這么干,除非你確實(shí)就是這樣總是一次就成功的天才,那你還看這篇文章干什么呢?我又不是寫給你們這些天才們看的。再就是有學(xué)會買好書、讀好書,關(guān)于計算機(jī)和軟件方面的書太多了,時間有限,比如有一個叫侯捷的家伙,幾乎寫的每本書都不錯,張國峰的C++編程也不錯,這只是我的個人意見啊,好書多著呢,列出來比這篇文章長好多倍,我就不多說了。還有一招,要是你運(yùn)氣好,能搞到一些著名軟件系統(tǒng)的源碼,好好讀讀吧,在此我只能告訴你,Linux操作系統(tǒng)的一些源碼不錯,是開放的,你可以合法地搞到,其它的不要說是我建議你侵犯知識版權(quán)??!
四、天生神力:成為系統(tǒng)分析員
本來就論述如何成為一名職業(yè)程序員而言,本文已基本完成任務(wù)了,但《菜根譚》有言:竭世機(jī)樞,似一滴投于巨壑,窮諸玄辯,若一毫置于太虛。既已乘興到此,何妨多置一毫于太虛呢,作者不才,干脆盡興寫算了。
你要是運(yùn)氣好,直接進(jìn)入了一個嚴(yán)格規(guī)范生產(chǎn)的軟件企業(yè)就業(yè),剛開始就應(yīng)該是按別人做好的軟件設(shè)計來實(shí)現(xiàn)編程,你可以有機(jī)會直接學(xué)習(xí)軟件設(shè)計,當(dāng)你積累的足夠多了,能夠?qū)ζ渲械囊恍┰O(shè)計提出好的改進(jìn)建議,而且干得又快又好,就會漸漸地展露頭角,我相信你終有一天成為一名軟件設(shè)計人員(注意,不是軟件產(chǎn)品設(shè)計人員),步入系統(tǒng)分析員的行列,但這還需其它的一些條件和自我修煉。如果你在一個不規(guī)范的軟件企業(yè)工作,那也不錯,你很可能直接就有機(jī)會進(jìn)行軟件設(shè)計,然后開發(fā)、測試,甚至還不得不自己定義需求,把軟件開發(fā)過程的各個環(huán)節(jié)走一個遍,當(dāng)然這樣對你的要求更高,而且你也不容易得到及時有益的指點(diǎn),在正態(tài)分布的情況下,你應(yīng)該是成長的很慢。但不管就業(yè)的單位如何,如果你決心要成為頂尖軟件職業(yè)選手,通常什么客觀困難都阻擋不了你,然而你個人的因素可能會阻止你的前進(jìn)。下面提出的觀點(diǎn)純屬一己之見,傷人自尊之處作者在此提前道歉,并建議你除非對本文有強(qiáng)烈的興趣,否則就請直接看第五節(jié)或放下別看了。丑話已說在前頭了,在各種軟件開發(fā)組織的發(fā)展過程中的事實(shí)也證明,只有少數(shù)程序員能成為系統(tǒng)分析員,我想這一點(diǎn)不是我杜撰的吧,因此你要是在看接下來的部分時感到氣憤難當(dāng),那也實(shí)在沒著,純屬活該,因?yàn)樽髡咧皇窃谡f明自己的觀點(diǎn)而已,你最多可以呲之以鼻,表示一下你的輕蔑好了,但沒有任何理由可以罵人!
作者自己沒有到微軟面試過,但身處軟件行業(yè),關(guān)于微軟的許多東東當(dāng)然還是有耳聞的,據(jù)說微軟招聘一名程序員要過五個已經(jīng)成為微軟程序員的面試關(guān),而且是一票否決制,又據(jù)說大多數(shù)面試題并非編程,而是一些有關(guān)邏輯和智力的題,作者私下也做過許多流傳的微軟面試題,并對此做法深以為然。程序的本質(zhì)就是邏輯,所以幾十年前就有人提出編程是一門藝術(shù),而藝術(shù)是要靠天份的,這一點(diǎn)少有人反對。一個人的邏輯能力可以不斷提高,但其能到達(dá)的終極邏輯能力的層次必定為其天生智力所限制,這一點(diǎn)就讓人不易接受了。好笑?。∪藗兛梢怨_承認(rèn)自己沒有某種或全部的藝術(shù)天份,但要說自己邏輯天份不夠,換句話說承認(rèn)自己笨、IQ不夠高,往往是要怒發(fā)沖冠的,其實(shí)這又有什么區(qū)別呢?話都說到這兒了,再次建議你如果不夠自信,就跳過這一節(jié)吧,直接看第五節(jié),好嗎?
好了,把話題說回來,你已經(jīng)成為一門合格的職業(yè)程序員了,如果要想成為從事軟件系統(tǒng)設(shè)計的職業(yè)系統(tǒng)分析員,第一件事就是悄悄找一個標(biāo)準(zhǔn)智商測試的網(wǎng)站或其它渠道,嚴(yán)格認(rèn)真的測一測自己的智商,如果IQ低于130(正常智商是110),就請別費(fèi)勁了,打消掉成為系統(tǒng)分析員的念頭吧!好!好!先請你冷靜一下,好好想想,其實(shí)微軟面試時就是在測你的智商和邏輯數(shù)學(xué)素質(zhì)呢,這就是本節(jié)的標(biāo)題為“天生神力”的原因,因?yàn)樵O(shè)計就是從無到有地進(jìn)行創(chuàng)造,無論是軟件還是其它行業(yè)都一樣,可以有借鑒的,沒有現(xiàn)成的,設(shè)計就是創(chuàng)造!如果你IQ在130以上,又決心要當(dāng)一名職業(yè)軟件系統(tǒng)分析員,其實(shí)你不過是要準(zhǔn)備好吃更大的苦而已,有什么好虛榮的呢?
修煉還是從基本功開始的,過程和成為一名職業(yè)程序員差不多。必須使用設(shè)計工具這一點(diǎn)是不用多說的。在工作中,你基本上遇到的是兩類方式的設(shè)計,一個是結(jié)構(gòu)化設(shè)計,另一個是面向?qū)ο笤O(shè)計,就個人經(jīng)驗(yàn)而言,面向?qū)ο蟮脑O(shè)計更好。如果你工作中不得不采用結(jié)構(gòu)化的設(shè)計,你必須熟練地掌握數(shù)據(jù)流圖和控制流圖的分析和設(shè)計,一般來講,如果你把一個軟件中用到的數(shù)據(jù)模型設(shè)計好了,針對功能化的流程,不難設(shè)計出數(shù)據(jù)流圖,但下一步設(shè)計控制流圖才是挑戰(zhàn),如果你按照需求走不通設(shè)計好的控制流圖,那么你或別人在按照這個設(shè)計編程實(shí)現(xiàn)時,必定也走不通,沒有奇跡會發(fā)生,還是在設(shè)計階段嚴(yán)格要求吧,又有一點(diǎn)需要牢記:返工是最慢的。當(dāng)你在進(jìn)行控制流圖的設(shè)計時,也不要妄想得到需求人員提供給你明確的指點(diǎn),通常他們要是能夠把需求的功能和操作次序?qū)懲暾脑?,你?yīng)該就感恩戴德了,從需求中整理出功能、操作的拓?fù)浯涡蚝蜅l件是你作為系統(tǒng)分析員的職責(zé)??纯矗菦]有一點(diǎn)圖論的基礎(chǔ)和拓?fù)鋵W(xué)的入門知識,你是當(dāng)不好一個職業(yè)系統(tǒng)分析員的,即使你天賦不錯,必要的數(shù)學(xué)和邏輯素質(zhì)仍然不可或缺。也不用氣餒,永遠(yuǎn)沒有最好的設(shè)計,只有更好的設(shè)計,反復(fù)地進(jìn)行設(shè)計迭代,勇于推翻舊的設(shè)計,你將快速進(jìn)步。如果你在工作中是采用面向?qū)ο筮M(jìn)行設(shè)計的,那就更有利了,有關(guān)面向?qū)ο笤O(shè)計的書太多了,不用作者在此多費(fèi)口舌,建議精讀一本經(jīng)典的書,比如北大邵維忠等編譯的《面向?qū)ο蟮姆治觥?,有些方法和技巧可能過時,但其邏輯的基本原理是非常正確的,其本質(zhì)是,你在邏輯上是如何認(rèn)識這個世界的,你就是如何設(shè)計軟件體系結(jié)構(gòu)的,然后讀讀其它書,觸類旁通,自己創(chuàng)造機(jī)會多實(shí)踐,成功自然會到來的,總之,不管是結(jié)構(gòu)化設(shè)計還是面向?qū)ο笤O(shè)計,評價一下自己的軟件系統(tǒng)設(shè)計方案吧,有好多指標(biāo)呢,比如是否均勻和平衡?局部獨(dú)立性強(qiáng)不強(qiáng)?有沒有歧異的結(jié)構(gòu)?有沒有層次太多或太少?有沒有某個層次太大、太廣?是不是邏輯結(jié)構(gòu)先復(fù)雜了再化簡的?還是只會設(shè)計簡單的,復(fù)雜不起來(這一點(diǎn)是笨哦,如果出現(xiàn)多次,請你不要意氣用事,轉(zhuǎn)行吧)?最重要的一點(diǎn),是否容易理解、實(shí)現(xiàn)和改進(jìn)?你自己會得出評價的。如果有機(jī)會看到別人的設(shè)計,一定不要錯過學(xué)習(xí)的機(jī)會,自己推導(dǎo)一遍,認(rèn)真比較比較,獲益會較多。
走到這一步,你就應(yīng)該關(guān)注設(shè)計模式了,首先還是學(xué)習(xí),這方面的好書有的是,但一般在工作中用到的設(shè)計模式較為單一,應(yīng)該多嘗試一下其它的設(shè)計模式。其次必須要明白設(shè)計模式不是設(shè)計思路,也不能代替設(shè)計思路,比方你要從A到B修一條路,設(shè)計模式只是讓你選擇,是修水泥的還是柏油的?是高架路還是普通的,但線路必須你自己定,而線路就是設(shè)計思路,模式對思路是有影響,但不能代替,所以如果你的智商高達(dá)250,我相信你直接用匯編語言也能寫出面向?qū)ο蟮某绦騺?。第三在此有一個陷阱,很多系統(tǒng)分析員生搬硬套設(shè)計模式,全然不懂如何融會貫通,在你的一項(xiàng)具體工作中,往往是以一種設(shè)計模式為主,其它模式為輔的,思維不拘泥于形式才是關(guān)鍵,而且也為你到達(dá)更高的軟件設(shè)計的境界做好準(zhǔn)備。
唉!都不知該怎么向下寫好了,因?yàn)橐堰_(dá)到作者水平的極限了,我胡亂說一點(diǎn),你湊合看吧。軟件設(shè)計最終的層次是:以無法為有法、以無限為有限,這句話是李小龍說的,不是我說的。再拾人牙慧一把,類比一個故事吧,金大俠在《倚天屠龍記》里講到張無忌初學(xué)太極,學(xué)會的標(biāo)志是把剛學(xué)的招數(shù)全忘了,記住的是太極的道理和精神,和李小龍有些相似喔,軟件設(shè)計也一樣,忘記所有的設(shè)計模式,隨心所欲進(jìn)行設(shè)計才是至高境界,所以你能到達(dá)多高的軟件設(shè)計的境界最終將取決于你的哲學(xué)素質(zhì),這一點(diǎn)實(shí)在是不好寫啊,你自己領(lǐng)悟吧!作者只有祝福了!
五、職業(yè)人的終極目標(biāo):全面修煉,成為Leader
這一節(jié)更不好寫,涉及到太多其它非技術(shù)方面的因素,特別是個人人生觀和世界觀的修煉,如果本帖的點(diǎn)擊率超過作者私下期望的一個數(shù)值,那我就爭取盡力厚著臉皮再補(bǔ)上吧。我只說一句,雖然大家都知道軟件開發(fā)是一個團(tuán)隊性的工作,但追求參與一個大型軟件系統(tǒng)的成功開發(fā),是一名軟件人員的本能,就像拿破侖說的不想當(dāng)元帥的士兵不是好士兵,所以不追求實(shí)現(xiàn)大系統(tǒng)的軟件人員,也不是一個好的職業(yè)軟件人員,但你只有成為Leader,領(lǐng)導(dǎo)一個優(yōu)秀的軟件開發(fā)團(tuán)隊,才有機(jī)會實(shí)現(xiàn)這個終極職業(yè)目標(biāo),對不對? 好吧,不管你現(xiàn)在的感受如何,我都謝謝你能讀到這里!我不習(xí)慣假謙虛,就不說什么作者水平有限,本文拋磚引玉,歡迎大家批評斧正之類的客套話了,雖然作者水平確實(shí)有限。所以我認(rèn)為你盡管有權(quán)砸磚,但實(shí)在沒必要搞回帖、或回罵、或頂之類的玩意兒,我只是盡興寫一點(diǎn)多年從事軟件開發(fā)工作的體驗(yàn),因此接下來我就高掛免戰(zhàn)牌,不回復(fù)任何回帖了。再次謝謝你能有耐心讀到這里!希望本文對你有所裨益,祝你成功!再見!
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/carefree31441/archive/2008/07/10/2635287.aspx
第五篇:C語言嵌入式系統(tǒng)編程修煉之道
C語言嵌入式系統(tǒng)編程修煉之道收藏
C語言嵌入式系統(tǒng)編程修煉之道——背景篇...1 C語言嵌入式系統(tǒng)編程修煉之道——軟件架構(gòu)篇...4 1.模塊劃分...4 2.多任務(wù)還是單任務(wù)...5 3.單任務(wù)程序典型架構(gòu)...6 4.中斷服務(wù)程序...7 5.硬件驅(qū)動模塊...9 6.C的面向?qū)ο蠡?..10 總結(jié)...10 C語言嵌入式系統(tǒng)編程修煉之道——內(nèi)存操作篇...12 1.數(shù)據(jù)指針...12 2.函數(shù)指針...13 3.數(shù)組vs.動態(tài)申請...14 4.關(guān)鍵字const 15 5.關(guān)鍵字volatile.16 6.CPU字長與存儲器位寬不一致處理...17 總結(jié)...18 C語言嵌入式系統(tǒng)編程修煉之道——屏幕操作篇...19 1.漢字處理...19 2.系統(tǒng)時間顯示...20 3.動畫顯示...21 4.菜單操作...22 5.模擬MessageBox函數(shù)...24 總結(jié)...26 C語言嵌入式系統(tǒng)編程修煉之道——鍵盤操作篇...27 1.處理功能鍵...27 2.處理數(shù)字鍵...28 3.整理用戶輸入...29 總結(jié)...30 C語言嵌入式系統(tǒng)編程修煉之道——性能優(yōu)化篇...31 1.使用宏定義...31 2.使用寄存器變量...31 3.內(nèi)嵌匯編...32 4.利用硬件特性...32 5.活用位操作...33 總結(jié)
C語言嵌入式系統(tǒng)編程修煉之道——背景篇 不同于一般形式的軟件編程,嵌入式系統(tǒng)編程建立在特定的硬件平臺上,勢必要求其編程語言具備較強(qiáng)的硬件直接操作能力。無疑,匯編語言具備這樣的特質(zhì)。但是,歸因于匯編語言開發(fā)過程的復(fù)雜性,它并不是嵌入式系統(tǒng)開發(fā)的一般選擇。而與之相比,C語言——一種“高級的低級”語言,則成為嵌入式系統(tǒng)開發(fā)的最佳選擇。筆者在嵌入式系統(tǒng)項(xiàng)目的開發(fā)過程中,一次又一次感受到C語言的精妙,沉醉于C語言給嵌入式開發(fā)帶來的便利。本文的目的在于進(jìn)行“C語言嵌入式系統(tǒng)開發(fā)的內(nèi)功心法”秀,一共包括25招。
圖1給出了本文的討論所基于的硬件平臺,實(shí)際上,這也是大多數(shù)嵌入式系統(tǒng)的硬件平臺。它包括兩部分:
(1)
以通用處理器為中心的協(xié)議處理模塊,用于網(wǎng)絡(luò)控制協(xié)議的處理;(2)
以數(shù)字信號處理器(DSP)為中心的信號處理模塊,用于調(diào)制、解調(diào)和數(shù)/模信號轉(zhuǎn)換。
本文的討論主要圍繞以通用處理器為中心的協(xié)議處理模塊進(jìn)行,因?yàn)樗嗟貭可娴骄唧w的C語言編程技巧。而DSP編程則重點(diǎn)關(guān)注具體的數(shù)字信號處理算法,主要涉及通信領(lǐng)域的知識,不是本文的討論重點(diǎn)。
著眼于討論普遍的嵌入式系統(tǒng)C編程技巧,系統(tǒng)的協(xié)議處理模塊沒有選擇特別的CPU,而是選擇了眾所周知的CPU芯片——80186,每一位學(xué)習(xí)過《微機(jī)原理》的讀者都應(yīng)該對此芯片有一個基本的認(rèn)識,且對其指令集比較熟悉。80186的字長是16位,可以尋址到的內(nèi)存空間為1MB,只有實(shí)地址模式。C語言編譯生成的指針為32位(雙字),高16位為段地址,低16位為段內(nèi)編譯,一段最多64KB。
圖1 系統(tǒng)硬件架構(gòu)
協(xié)議處理模塊中的FLASH和RAM幾乎是每個嵌入式系統(tǒng)的必備設(shè)備,前者用于存儲程序,后者則是程序運(yùn)行時指令及數(shù)據(jù)的存放位置。系統(tǒng)所選擇的FLASH和RAM的位寬都為16位,與CPU一致。
實(shí)時鐘芯片可以為系統(tǒng)定時,給出當(dāng)前的年、月、日及具體時間(小時、分、秒及毫秒),可以設(shè)定其經(jīng)過一段時間即向CPU提出中斷或設(shè)定報警時間到來時向CPU提出中斷(類似鬧鐘功能)。
NVRAM(非易失去性RAM)具有掉電不丟失數(shù)據(jù)的特性,可以用于保存系統(tǒng)的設(shè)置信息,譬如網(wǎng)絡(luò)協(xié)議參數(shù)等。在系統(tǒng)掉電或重新啟動后,仍然可以讀取先前的設(shè)置信息。其位寬為8位,比CPU字長小。文章特意選擇一個與CPU字長不一致的存儲芯片,為后文中一節(jié)的討論創(chuàng)造條件。
UART則完成CPU并行數(shù)據(jù)傳輸與RS-232串行數(shù)據(jù)傳輸?shù)霓D(zhuǎn)換,它可以在接收到[1~MAX_BUFFER]字節(jié)后向CPU提出中斷,MAX_BUFFER為UART芯片存儲接收到字節(jié)的最大緩沖區(qū)。
鍵盤控制器和顯示控制器則完成系統(tǒng)人機(jī)界面的控制。以上提供的是一個較完備的嵌入式系統(tǒng)硬件架構(gòu),實(shí)際的系統(tǒng)可能包含更少的外設(shè)。之所以選擇一個完備的系統(tǒng),是為了后文更全面的討論嵌入式系統(tǒng)C語言編程技巧的方方面面,所有設(shè)備都會成為后文的分析目標(biāo)。
嵌入式系統(tǒng)需要良好的軟件開發(fā)環(huán)境的支持,由于嵌入式系統(tǒng)的目標(biāo)機(jī)資源受限,不可能在其上建立龐大、復(fù)雜的開發(fā)環(huán)境,因而其開發(fā)環(huán)境和目標(biāo)運(yùn)行環(huán)境相互分離。因此,嵌入式應(yīng)用軟件的開發(fā)方式一般是,在宿主機(jī)(Host)上建立開發(fā)環(huán)境,進(jìn)行應(yīng)用程序編碼和交叉編譯,然后宿主機(jī)同目標(biāo)機(jī)(Target)建立連接,將應(yīng)用程序下載到目標(biāo)機(jī)上進(jìn)行交叉調(diào)試,經(jīng)過調(diào)試和優(yōu)化,最后將應(yīng)用程序固化到目標(biāo)機(jī)中實(shí)際運(yùn)行。
CAD-UL是適用于x86處理器的嵌入式應(yīng)用軟件開發(fā)環(huán)境,它運(yùn)行在Windows操作系統(tǒng)之上,可生成x86處理器的目標(biāo)代碼并通過PC機(jī)的COM口(RS-232串口)或以太網(wǎng)口下載到目標(biāo)機(jī)上運(yùn)行,如圖2。其駐留于目標(biāo)機(jī)FLASH存儲器中的monitor程序可以監(jiān)控宿主機(jī)Windows調(diào)試平臺上的用戶調(diào)試指令,獲取CPU寄存器的值及目標(biāo)機(jī)存儲空間、I/O空間的內(nèi)容。圖2 交叉開發(fā)環(huán)境
后續(xù)章節(jié)將從軟件架構(gòu)、內(nèi)存操作、屏幕操作、鍵盤操作、性能優(yōu)化等多方面闡述C語言嵌入式系統(tǒng)的編程技巧。軟件架構(gòu)是一個宏觀概念,與具體硬件的聯(lián)系不大;內(nèi)存操作主要涉及系統(tǒng)中的FLASH、RAM和NVRAM芯片;屏幕操作則涉及顯示控制器和實(shí)時鐘;鍵盤操作主要涉及鍵盤控制器;性能優(yōu)化則給出一些具體的減小程序時間、空間消耗的技巧。
本文即將講述的25個主題可分為兩類,一類是編程技巧,有很強(qiáng)的適用性;一類則介紹嵌入式系統(tǒng)編程的一般常識,具有一定的理論意義。So, let’s go.C語言嵌入式系統(tǒng)編程修煉之道——軟件架構(gòu)篇 1.模塊劃分
模塊劃分的“劃”是規(guī)劃的意思,意指怎樣合理的將一個很大的軟件劃分為一系列功能獨(dú)立的部分合作完成系統(tǒng)的需求。C語言作為一種結(jié)構(gòu)化的程序設(shè)計語言,在模塊的劃分上主要依據(jù)功能(依功能進(jìn)行劃分在面向?qū)ο笤O(shè)計中成為一個錯誤,牛頓定律遇到了相對論),C語言模塊化程序設(shè)計需理解如下概念:(1)
模塊即是一個.c文件和一個.h文件的結(jié)合,頭文件(.h)中是對于該模塊接口的聲明;
(2)
某模塊提供給其它模塊調(diào)用的外部函數(shù)及數(shù)據(jù)需在.h中文件中冠以extern關(guān)鍵字聲明;
(3)
模塊內(nèi)的函數(shù)和全局變量需在.c文件開頭冠以static關(guān)鍵字聲明;(4)
永遠(yuǎn)不要在.h文件中定義變量!定義變量和聲明變量的區(qū)別在于定義會產(chǎn)生內(nèi)存分配的操作,是匯編階段的概念;而聲明則只是告訴包含該聲明的模塊在連接階段從其它模塊尋找外部函數(shù)和變量。如: /*module1.h*/ int a = 5;
/* 在模塊1的.h文件中定義int a */
/*module1.c*/ #include “module1.h”
/* 在模塊1中包含模塊1的.h文件 */ /*module2.c*/ #include “module1.h”
/* 在模塊2中包含模塊1的.h文件 */ /*module3.c*/ #include “module1.h”
/* 在模塊3中包含模塊1的.h文件 */ 以上程序的結(jié)果是在模塊1、2、3中都定義了整型變量a,a在不同的模塊中對應(yīng)不同的地址單元,這個世界上從來不需要這樣的程序。正確的做法是: /*module1.h*/ extern int a;
/* 在模塊1的.h文件中聲明int a */ /*module1.c*/ #include “module1.h”
/* 在模塊1中包含模塊1的.h文件 */ int a = 5;
/* 在模塊1的.c文件中定義int a */ /*module2.c*/ #include “module1.h”
/* 在模塊2中包含模塊1的.h文件 */
/*module3.c*/ #include “module1.h”
/* 在模塊3中包含模塊1的.h文件 */ 這樣如果模塊1、2、3操作a的話,對應(yīng)的是同一片內(nèi)存單元。一個嵌入式系統(tǒng)通常包括兩類模塊:
(1)硬件驅(qū)動模塊,一種特定硬件對應(yīng)一個模塊;
(2)軟件功能模塊,其模塊的劃分應(yīng)滿足低偶合、高內(nèi)聚的要求。2.多任務(wù)還是單任務(wù)
所謂“單任務(wù)系統(tǒng)”是指該系統(tǒng)不能支持多任務(wù)并發(fā)操作,宏觀串行地執(zhí)行一個任務(wù)。而多任務(wù)系統(tǒng)則可以宏觀并行(微觀上可能串行)地“同時”執(zhí)行多個任務(wù)。
多任務(wù)的并發(fā)執(zhí)行通常依賴于一個多任務(wù)操作系統(tǒng)(OS),多任務(wù)OS的核心是系統(tǒng)調(diào)度器,它使用任務(wù)控制塊(TCB)來管理任務(wù)調(diào)度功能。TCB包括任務(wù)的當(dāng)前狀態(tài)、優(yōu)先級、要等待的事件或資源、任務(wù)程序碼的起始地址、初始堆棧指針等信息。調(diào)度器在任務(wù)被激活時,要用到這些信息。此外,TCB還被用來存放任務(wù)的“上下文”(context)。任務(wù)的上下文就是當(dāng)一個執(zhí)行中的任務(wù)被停止時,所要保存的所有信息。通常,上下文就是計算機(jī)當(dāng)前的狀態(tài),也即各個寄存器的內(nèi)容。當(dāng)發(fā)生任務(wù)切換時,當(dāng)前運(yùn)行的任務(wù)的上下文被存入TCB,并將要被執(zhí)行的任務(wù)的上下文從它的TCB中取出,放入各個寄存器中。嵌入式多任務(wù)OS的典型例子有Vxworks、ucLinux等。嵌入式OS并非遙不可及的神壇之物,我們可以用不到1000行代碼實(shí)現(xiàn)一個針對80186處理器的功能最簡單的OS內(nèi)核,作者正準(zhǔn)備進(jìn)行此項(xiàng)工作,希望能將心得貢獻(xiàn)給大家。
究竟選擇多任務(wù)還是單任務(wù)方式,依賴于軟件的體系是否龐大。例如,絕大多數(shù)手機(jī)程序都是多任務(wù)的,但也有一些小靈通的協(xié)議棧是單任務(wù)的,沒有操作系統(tǒng),它們的主程序輪流調(diào)用各個軟件模塊的處理程序,模擬多任務(wù)環(huán)境。3.單任務(wù)程序典型架構(gòu)
(1)從CPU復(fù)位時的指定地址開始執(zhí)行;(2)跳轉(zhuǎn)至匯編代碼startup處執(zhí)行;
(3)跳轉(zhuǎn)至用戶主程序main執(zhí)行,在main中完成: a.初試化各硬件設(shè)備;
b.初始化各軟件模塊; c.進(jìn)入死循環(huán)(無限循環(huán)),調(diào)用各模塊的處理函數(shù)
用戶主程序和各模塊的處理函數(shù)都以C語言完成。用戶主程序最后都進(jìn)入了一個死循環(huán),其首選方案是: while(1){ } 有的程序員這樣寫: for(;;){ } 這個語法沒有確切表達(dá)代碼的含義,我們從for(;;)看不出什么,只有弄明白for(;;)在C語言中意味著無條件循環(huán)才明白其意。下面是幾個“著名”的死循環(huán):(1)操作系統(tǒng)是死循環(huán);(2)WIN32程序是死循環(huán);(3)嵌入式系統(tǒng)軟件是死循環(huán);
(4)多線程程序的線程處理函數(shù)是死循環(huán)。你可能會辯駁,大聲說:“凡事都不是絕對的,2、3、4都可以不是死循環(huán)”。Yes,you are right,但是你得不到鮮花和掌聲。實(shí)際上,這是一個沒有太大意義的牛角尖,因?yàn)檫@個世界從來不需要一個處理完幾個消息就喊著要OS殺死它的WIN32程序,不需要一個剛開始RUN就自行了斷的嵌入式系統(tǒng),不需要莫名其妙啟動一個做一點(diǎn)事就干掉自己的線程。有時候,過于嚴(yán)謹(jǐn)制造的不是便利而是麻煩。君不見,五層的TCP/IP協(xié)議棧超越嚴(yán)謹(jǐn)?shù)腎SO/OSI七層協(xié)議棧大行其道成為事實(shí)上的標(biāo)準(zhǔn)? 經(jīng)常有網(wǎng)友討論:
printf(“%d,%d”,++i,i++);
/* 輸出是什么?*/ c = a+++b;
/* c=? */ 等類似問題。面對這些問題,我們只能發(fā)出由衷的感慨:世界上還有很多有意義的事情等著我們?nèi)ハ瘮z入的食物。實(shí)際上,嵌入式系統(tǒng)要運(yùn)行到世界末日。4.中斷服務(wù)程序
中斷是嵌入式系統(tǒng)中重要的組成部分,但是在標(biāo)準(zhǔn)C中不包含中斷。許多編譯開發(fā)商在標(biāo)準(zhǔn)C上增加了對中斷的支持,提供新的關(guān)鍵字用于標(biāo)示中斷服務(wù)程序(ISR),類似于__interrupt、#program interrupt等。當(dāng)一個函數(shù)被定義為ISR的時候,編譯器會自動為該函數(shù)增加中斷服務(wù)程序所需要的中斷現(xiàn)場入棧和出棧代碼。
中斷服務(wù)程序需要滿足如下要求:(1)不能返回值;
(2)不能向ISR傳遞參數(shù);
(3)ISR應(yīng)該盡可能的短小精悍;
(4)printf(char * lpFormatString,?)函數(shù)會帶來重入和性能問題,不能在ISR中采用。
在某項(xiàng)目的開發(fā)中,我們設(shè)計了一個隊列,在中斷服務(wù)程序中,只是將中斷類型添加入該隊列中,在主程序的死循環(huán)中不斷掃描中斷隊列是否有中斷,有則取出隊列中的第一個中斷類型,進(jìn)行相應(yīng)處理。/* 存放中斷的隊列 */ typedef struct tagIntQueue { int intType;
/* 中斷類型 */ struct tagIntQueue *next;}IntQueue;
IntQueue lpIntQueueHead;
__interrupt ISRexample(){
int intType;
intType = GetSystemType();QueueAddTail(lpIntQueueHead, intType);/* 在隊列尾加入新的中斷 */ } 在主程序循環(huán)中判斷是否有中斷: While(1){ If(!IsIntQueueEmpty())
{
intType = GetFirstInt();
switch(intType)
/* 是不是很象WIN32程序的消息解析函數(shù)? */
{
/* 對,我們的中斷類型解析很類似于消息驅(qū)動 */
case xxx:
/* 我們稱其為“中斷驅(qū)動”吧? */
…
break;
case xxx:
…
break;
…
} }
} 按上述方法設(shè)計的中斷服務(wù)程序很小,實(shí)際的工作都交由主程序執(zhí)行了。5.硬件驅(qū)動模塊
一個硬件驅(qū)動模塊通常應(yīng)包括如下函數(shù):(1)中斷服務(wù)程序ISR(2)硬件初始化
a.修改寄存器,設(shè)置硬件參數(shù)(如UART應(yīng)設(shè)置其波特率,AD/DA設(shè)備應(yīng)設(shè)置其采樣速率等);
b.將中斷服務(wù)程序入口地址寫入中斷向量表: /* 設(shè)置中斷向量表 */
m_myPtr = make_far_pointer(0l);/* 返回void far型指針void far * */
m_myPtr += ITYPE_UART;/* ITYPE_UART: uart中斷服務(wù)程序 */ /* 相對于中斷向量表首地址的偏移 */
*m_myPtr = &UART _Isr;
/* UART _Isr:UART的中斷服務(wù)程序 */(3)設(shè)置CPU針對該硬件的控制線
a.如果控制線可作PIO(可編程I/O)和控制信號用,則設(shè)置CPU內(nèi)部對應(yīng)寄存器使其作為控制信號;
b.設(shè)置CPU內(nèi)部的針對該設(shè)備的中斷屏蔽位,設(shè)置中斷方式(電平觸發(fā)還是邊緣觸發(fā))。
(4)提供一系列針對該設(shè)備的操作接口函數(shù)。例如,對于LCD,其驅(qū)動模塊應(yīng)提供繪制像素、畫線、繪制矩陣、顯示字符點(diǎn)陣等函數(shù);而對于實(shí)時鐘,其驅(qū)動模塊則需提供獲取時間、設(shè)置時間等函數(shù)。6.C的面向?qū)ο蠡?/p>
在面向?qū)ο蟮恼Z言里面,出現(xiàn)了類的概念。類是對特定數(shù)據(jù)的特定操作的集合體。類包含了兩個范疇:數(shù)據(jù)和操作。而C語言中的struct僅僅是數(shù)據(jù)的集合,我們可以利用函數(shù)指針將struct模擬為一個包含數(shù)據(jù)和操作的“類”。下面的C程序模擬了一個最簡單的“類”: #ifndef C_Class
#define C_Class struct #endif C_Class A {
C_Class A *A_this;
/* this指針 */
void(*Foo)(C_Class A *A_this);/* 行為:函數(shù)指針 */
int a;
/* 數(shù)據(jù) */
int b;};我們可以利用C語言模擬出面向?qū)ο蟮娜齻€特性:封裝、繼承和多態(tài),但是更多的時候,我們只是需要將數(shù)據(jù)與行為封裝以解決軟件結(jié)構(gòu)混亂的問題。C模擬面向?qū)ο笏枷氲哪康牟辉谟谀M行為本身,而在于解決某些情況下使用C語言編程時程序整體框架結(jié)構(gòu)分散、數(shù)據(jù)和函數(shù)脫節(jié)的問題。我們在后續(xù)章節(jié)會看到這樣的例子??偨Y(jié)
本篇介紹了嵌入式系統(tǒng)編程軟件架構(gòu)方面的知識,主要包括模塊劃分、多任務(wù)還是單任務(wù)選取、單任務(wù)程序典型架構(gòu)、中斷服務(wù)程序、硬件驅(qū)動模塊設(shè)計等,從宏觀上給出了一個嵌入式系統(tǒng)軟件所包含的主要元素。
請記?。很浖Y(jié)構(gòu)是軟件的靈魂!結(jié)構(gòu)混亂的程序面目可憎,調(diào)試、測試、維護(hù)、升級都極度困難。
一個高尚的程序員應(yīng)該是寫出如藝術(shù)作品般程序的程序員。
C語言嵌入式系統(tǒng)編程修煉之道——內(nèi)存操作篇 1.數(shù)據(jù)指針
在嵌入式系統(tǒng)的編程中,常常要求在特定的內(nèi)存單元讀寫內(nèi)容,匯編有對應(yīng)的MOV指令,而除C/C++以外的其它編程語言基本沒有直接訪問絕對地址的能力。在嵌入式系統(tǒng)的實(shí)際調(diào)試中,多借助C語言指針?biāo)哂械膶^對地址單元內(nèi)容的讀寫能力。以指針直接操作內(nèi)存多發(fā)生在如下幾種情況:
(1)
某I/O芯片被定位在CPU的存儲空間而非I/O空間,而且寄存器對應(yīng)于某特定地址;
(2)
兩個CPU之間以雙端口RAM通信,CPU需要在雙端口RAM的特定單元(稱為mail box)書寫內(nèi)容以在對方CPU產(chǎn)生中斷;
(3)
讀取在ROM或FLASH的特定單元所燒錄的漢字和英文字模。譬如:
unsigned char *p =(unsigned char *)0xF000FF00;*p=11;以上程序的意義為在絕對地址0xF0000+0xFF00(80186使用16位段地址和16位偏移地址)寫入11。在使用絕對地址指針時,要注意指針自增自減操作的結(jié)果取決于指針指向的數(shù)據(jù)類別。上例中p++后的結(jié)果是p= 0xF000FF01,若p指向int,即: int *p =(int *)0xF000FF00;p++(或++p)的結(jié)果等同于:p = p+sizeof(int),而p—(或—p)的結(jié)果是p = p-sizeof(int)。同理,若執(zhí)行:
long int *p =(long int *)0xF000FF00;則p++(或++p)的結(jié)果等同于:p = p+sizeof(long int),而p—(或—p)的結(jié)果是p = p-sizeof(long int)。
記?。篊PU以字節(jié)為單位編址,而C語言指針以指向的數(shù)據(jù)類型長度作自增和自減。理解這一點(diǎn)對于以指針直接操作內(nèi)存是相當(dāng)重要的。2.函數(shù)指針
首先要理解以下三個問題:
(1)C語言中函數(shù)名直接對應(yīng)于函數(shù)生成的指令代碼在內(nèi)存中的地址,因此函數(shù)名可以直接賦給指向函數(shù)的指針;
(2)調(diào)用函數(shù)實(shí)際上等同于“調(diào)轉(zhuǎn)指令+參數(shù)傳遞處理+回歸位置入?!?,本質(zhì)上最核心的操作是將函數(shù)生成的目標(biāo)代碼的首地址賦給CPU的PC寄存器;(3)因?yàn)楹瘮?shù)調(diào)用的本質(zhì)是跳轉(zhuǎn)到某一個地址單元的code去執(zhí)行,所以可以“調(diào)用”一個根本就不存在的函數(shù)實(shí)體,暈?請往下看: 請拿出你可以獲得的任何一本大學(xué)《微型計算機(jī)原理》教材,書中講到,186 CPU啟動后跳轉(zhuǎn)至絕對地址0xFFFF0(對應(yīng)C語言指針是0xF000FFF0,0xF000為段地址,0xFFF0為段內(nèi)偏移)執(zhí)行,請看下面的代碼:
typedef void(*lpFunction)();
/* 定義一個無參數(shù)、無返回類型的 */ /* 函數(shù)指針類型 */ lpFunction lpReset =(lpFunction)0xF000FFF0;
/* 定義一個函數(shù)指針,指向*/ /* CPU啟動后所執(zhí)行第一條指令的位置 */ lpReset();
/* 調(diào)用函數(shù) */ 在以上的程序中,我們根本沒有看到任何一個函數(shù)實(shí)體,但是我們卻執(zhí)行了這樣的函數(shù)調(diào)用:lpReset(),它實(shí)際上起到了“軟重啟”的作用,跳轉(zhuǎn)到CPU啟動后第一條要執(zhí)行的指令的位置。
記住:函數(shù)無它,唯指令集合耳;你可以調(diào)用一個沒有函數(shù)體的函數(shù),本質(zhì)上只是換一個地址開始執(zhí)行指令!3.數(shù)組vs.動態(tài)申請
在嵌入式系統(tǒng)中動態(tài)內(nèi)存申請存在比一般系統(tǒng)編程時更嚴(yán)格的要求,這是因?yàn)榍度胧较到y(tǒng)的內(nèi)存空間往往是十分有限的,不經(jīng)意的內(nèi)存泄露會很快導(dǎo)致系統(tǒng)的崩潰。
所以一定要保證你的malloc和free成對出現(xiàn),如果你寫出這樣的一段程序: char * function(void){
char *p;
p =(char *)malloc(…);
if(p==NULL)?;
?
/* 一系列針對p的操作 */ return p;} 在某處調(diào)用function(),用完function中動態(tài)申請的內(nèi)存后將其free,如下: char *q = function();? free(q);上述代碼明顯是不合理的,因?yàn)檫`反了malloc和free成對出現(xiàn)的原則,即“誰申請,就由誰釋放”原則。不滿足這個原則,會導(dǎo)致代碼的耦合度增大,因?yàn)橛脩粼谡{(diào)用function函數(shù)時需要知道其內(nèi)部細(xì)節(jié)!
正確的做法是在調(diào)用處申請內(nèi)存,并傳入function函數(shù),如下: char *p=malloc(…);if(p==NULL)?;function(p);? free(p);p=NULL;而函數(shù)function則接收參數(shù)p,如下: void function(char *p){ ?
/* 一系列針對p的操作 */ } 基本上,動態(tài)申請內(nèi)存方式可以用較大的數(shù)組替換。對于編程新手,筆者推薦你盡量采用數(shù)組!嵌入式系統(tǒng)可以以博大的胸襟接收瑕疵,而無法“海納”錯誤。畢竟,以最笨的方式苦練神功的郭靖勝過機(jī)智聰明卻范政治錯誤走反革命道路的楊康。
給出原則:
(1)盡可能的選用數(shù)組,數(shù)組不能越界訪問(真理越過一步就是謬誤,數(shù)組越過界限就光榮地成全了一個混亂的嵌入式系統(tǒng));
(2)如果使用動態(tài)申請,則申請后一定要判斷是否申請成功了,并且malloc和free應(yīng)成對出現(xiàn)!4.關(guān)鍵字const const意味著“只讀”。區(qū)別如下代碼的功能非常重要,也是老生長嘆,如果你還不知道它們的區(qū)別,而且已經(jīng)在程序界摸爬滾打多年,那只能說這是一個悲哀: const int a;int const a;const int *a;int * const a;int const * a const;(1)關(guān)鍵字const的作用是為給讀你代碼的人傳達(dá)非常有用的信息。例如,在函數(shù)的形參前添加const關(guān)鍵字意味著這個參數(shù)在函數(shù)體內(nèi)不會被修改,屬于“輸入?yún)?shù)”。在有多個形參的時候,函數(shù)的調(diào)用者可以憑借參數(shù)前是否有const關(guān)鍵字,清晰的辨別哪些是輸入?yún)?shù),哪些是可能的輸出參數(shù)。
(2)合理地使用關(guān)鍵字const可以使編譯器很自然地保護(hù)那些不希望被改變的參數(shù),防止其被無意的代碼修改,這樣可以減少bug的出現(xiàn)。const在C++語言中則包含了更豐富的含義,而在C語言中僅意味著:“只能讀的普通變量”,可以稱其為“不能改變的變量”(這個說法似乎很拗口,但卻最準(zhǔn)確的表達(dá)了C語言中const的本質(zhì)),在編譯階段需要的常數(shù)仍然只能以#define宏定義!故在C語言中如下程序是非法的: const int SIZE = 10;char a[SIZE];/* 非法:編譯階段不能用到變量 */ 5.關(guān)鍵字volatile C語言編譯器會對用戶書寫的代碼進(jìn)行優(yōu)化,譬如如下代碼: int a,b,c;a = inWord(0x100);/*讀取I/O空間0x100端口的內(nèi)容存入a變量*/ b = a;a = inWord(0x100);/*再次讀取I/O空間0x100端口的內(nèi)容存入a變量*/ c = a;很可能被編譯器優(yōu)化為: int a,b,c;a = inWord(0x100);/*讀取I/O空間0x100端口的內(nèi)容存入a變量*/ b = a;c = a;但是這樣的優(yōu)化結(jié)果可能導(dǎo)致錯誤,如果I/O空間0x100端口的內(nèi)容在執(zhí)行第一次讀操作后被其它程序?qū)懭胄轮担瑒t其實(shí)第2次讀操作讀出的內(nèi)容與第一次不同,b和c的值應(yīng)該不同。在變量a的定義前加上volatile關(guān)鍵字可以防止編譯器的類似優(yōu)化,正確的做法是: volatile int a;
volatile變量可能用于如下幾種情況:
(1)并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器,例中的代碼屬于此類);(2)一個中斷服務(wù)子程序中會訪問到的非自動變量(也就是全局變量);(3)多線程應(yīng)用中被幾個任務(wù)共享的變量。6.CPU字長與存儲器位寬不一致處理
在背景篇中提到,本文特意選擇了一個與CPU字長不一致的存儲芯片,就是為了進(jìn)行本節(jié)的討論,解決CPU字長與存儲器位寬不一致的情況。80186的字長為16,而NVRAM的位寬為8,在這種情況下,我們需要為NVRAM提供讀寫字節(jié)、字的接口,如下: typedef unsigned char BYTE;typedef unsigned int WORD;
/* 函數(shù)功能:讀NVRAM中字節(jié)
* 參數(shù):wOffset,讀取位置相對NVRAM基地址的偏移
* 返回:讀取到的字節(jié)值 */ extern BYTE ReadByteNVRAM(WORD wOffset){
LPBYTE lpAddr =(BYTE*)(NVRAM + wOffset * 2);/* 為什么偏移要×2? */
return *lpAddr;}
/* 函數(shù)功能:讀NVRAM中字
* 參數(shù):wOffset,讀取位置相對NVRAM基地址的偏移
* 返回:讀取到的字 */ extern WORD ReadWordNVRAM(WORD wOffset){
WORD wTmp = 0;
LPBYTE lpAddr;
/* 讀取高位字節(jié) */
lpAddr =(BYTE*)(NVRAM + wOffset * 2);
/* 為什么偏移要×2? */
wTmp +=(*lpAddr)*256;
/* 讀取低位字節(jié) */
lpAddr =(BYTE*)(NVRAM +(wOffset +1)* 2);
/* 為什么偏移要×2? */
wTmp += *lpAddr;
return wTmp;}
/* 函數(shù)功能:向NVRAM中寫一個字節(jié)
*參數(shù):wOffset,寫入位置相對NVRAM基地址的偏移 *
byData,欲寫入的字節(jié) */ extern void WriteByteNVRAM(WORD wOffset, BYTE byData){
… }
/* 函數(shù)功能:向NVRAM中寫一個字 */ *參數(shù):wOffset,寫入位置相對NVRAM基地址的偏移 *
wData,欲寫入的字 */ extern void WriteWordNVRAM(WORD wOffset, WORD wData){
… } 子貢問曰:Why偏移要乘以2? 子曰:請看圖1,16位80186與8位NVRAM之間互連只能以地址線A1對其A0,CPU本身的A0與NVRAM不連接。因此,NVRAM的地址只能是偶數(shù)地址,故每次以2為單位前進(jìn)!
圖1 CPU與NVRAM地址線連接
子貢再問:So why 80186的地址線A0不與NVRAM的A0連接? 子曰:請看《IT論語》之《微機(jī)原理篇》,那里面講述了關(guān)于計算機(jī)組成的圣人之道。總結(jié)
本篇主要講述了嵌入式系統(tǒng)C編程中內(nèi)存操作的相關(guān)技巧。掌握并深入理解關(guān)于數(shù)據(jù)指針、函數(shù)指針、動態(tài)申請內(nèi)存、const及volatile關(guān)鍵字等的相關(guān)知識,是一個優(yōu)秀的C語言程序設(shè)計師的基本要求。當(dāng)我們已經(jīng)牢固掌握了上述技巧后,我們就已經(jīng)學(xué)會了C語言的99%,因?yàn)镃語言最精華的內(nèi)涵皆在內(nèi)存操作中體現(xiàn)。
我們之所以在嵌入式系統(tǒng)中使用C語言進(jìn)行程序設(shè)計,99%是因?yàn)槠鋸?qiáng)大的內(nèi)存操作能力!
如果你愛編程,請你愛C語言; 如果你愛C語言,請你愛指針; 如果你愛指針,請你愛指針的指針!
C語言嵌入式系統(tǒng)編程修煉之道——屏幕操作篇 1.漢字處理
現(xiàn)在要解決的問題是,嵌入式系統(tǒng)中經(jīng)常要使用的并非是完整的漢字庫,往往只是需要提供數(shù)量有限的漢字供必要的顯示功能。例如,一個微波爐的LCD上沒有必要提供顯示“電子郵件”的功能;一個提供漢字顯示功能的空調(diào)的LCD上不需要顯示一條“短消息”,諸如此類。但是一部手機(jī)、小靈通則通常需要包括較完整的漢字庫。
如果包括的漢字庫較完整,那么,由內(nèi)碼計算出漢字字模在庫中的偏移是十分簡單的:漢字庫是按照區(qū)位的順序排列的,前一個字節(jié)為該漢字的區(qū)號,后一個字節(jié)為該字的位號。每一個區(qū)記錄94個漢字,位號則為該字在該區(qū)中的位置。因此,漢字在漢字庫中的具體位置計算公式為:94*(區(qū)號-1)+位號-1。減1是因?yàn)閿?shù)組是以0為開始而區(qū)號位號是以1為開始的。只需乘上一個漢字字模占用的字節(jié)數(shù)即可,即:(94*(區(qū)號-1)+位號-1)*一個漢字字模占用字節(jié)數(shù),以16*16點(diǎn)陣字庫為例,計算公式則為:(94*(區(qū)號-1)+(位號-1))*32。漢字庫中從該位置起的32字節(jié)信息記錄了該字的字模信息。
對于包含較完整漢字庫的系統(tǒng)而言,我們可以以上述規(guī)則計算字模的位置。但是如果僅僅是提供少量漢字呢?譬如幾十至幾百個?最好的做法是: 定義宏:
# define EX_FONT_CHAR(value)
# define EX_FONT_UNICODE_VAL(value)(value), # define EX_FONT_ANSI_VAL(value)(value), 定義結(jié)構(gòu)體:
typedef struct _wide_unicode_font16x16 { WORD value;
/* 內(nèi)碼 */ BYTE data[32];/* 字模點(diǎn)陣 */ }Unicode;#define CHINESE_CHAR_NUM ?
/* 漢字?jǐn)?shù)量 */ 字模的存儲用數(shù)組:
Unicode chinese[CHINESE_CHAR_NUM] = { {
EX_FONT_CHAR(“業(yè)”)
EX_FONT_UNICODE_VAL(0x4e1a)
{0x04, 0x40, 0x04, 0x40, 0x04, 0x40, 0x04, 0x44, 0x44, 0x46, 0x24, 0x4c, 0x24, 0x48, 0x14, 0x50, 0x1c, 0x50,0x14, 0x60, 0x04, 0x40, 0x04, 0x40, 0x04, 0x44, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00}
},{
EX_FONT_CHAR(“中”)
EX_FONT_UNICODE_VAL(0x4e2d)
{0x01, 0x00, 0x01, 0x00, 0x21, 0x08, 0x3f, 0xfc, 0x21, 0x08, 0x21, 0x08, 0x21, 0x08, 0x21, 0x08, 0x21, 0x08,0x3f, 0xf8, 0x21, 0x08, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00}
},{
EX_FONT_CHAR(“云”)
EX_FONT_UNICODE_VAL(0x4e91)
{0x00, 0x00, 0x00, 0x30, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xfe, 0x03, 0x00, 0x07, 0x00,0x06, 0x40, 0x0c, 0x20, 0x18, 0x10, 0x31, 0xf8, 0x7f, 0x0c, 0x20, 0x08, 0x00, 0x00}
},{
EX_FONT_CHAR(“件”)
EX_FONT_UNICODE_VAL(0x4ef6)
{0x10, 0x40, 0x1a, 0x40, 0x13, 0x40, 0x32, 0x40, 0x23, 0xfc, 0x64, 0x40, 0xa4, 0x40, 0x28, 0x40, 0x2f, 0xfe,0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40}
} } 要顯示特定漢字的時候,只需要從數(shù)組中查找內(nèi)碼與要求漢字內(nèi)碼相同的即可獲得字模。如果前面的漢字在數(shù)組中以內(nèi)碼大小順序排列,那么可以以二分查找法更高效的查找到漢字的字模。
這是一種很有效的組織小漢字庫的方法,它可以保證程序有很好的結(jié)構(gòu)。2.系統(tǒng)時間顯示
從NVRAM中可以讀取系統(tǒng)的時間,系統(tǒng)一般借助NVRAM產(chǎn)生的秒中斷每秒讀取一次當(dāng)前時間并在LCD上顯示。關(guān)于時間的顯示,有一個效率問題。因?yàn)闀r間有其特殊性,那就是60秒才有一次分鐘的變化,60分鐘才有一次小時變化,如果我們每次都將讀取的時間在屏幕上完全重新刷新一次,則浪費(fèi)了大量的系統(tǒng)時間。
一個較好的辦法是我們在時間顯示函數(shù)中以靜態(tài)變量分別存儲小時、分鐘、秒,只有在其內(nèi)容發(fā)生變化的時候才更新其顯示。extern void DisplayTime(…){
static BYTE byHour,byMinute,bySecond;
BYTE byNewHour, byNewMinute, byNewSecond;
byNewHour = GetSysHour();
byNewMinute = GetSysMinute();
byNewSecond = GetSysSecond();
if(byNewHour!= byHour)
{ ?
/* 顯示小時 */ byHour = byNewHour;}
if(byNewMinute!= byMinute)
{ ?
/* 顯示分鐘 */ byMinute = byNewMinute;}
if(byNewSecond!= bySecond)
{ ?
/* 顯示秒鐘 */ bySecond = byNewSecond;} } 這個例子也可以順便作為C語言中static關(guān)鍵字強(qiáng)大威力的證明。當(dāng)然,在C++語言里,static具有了更加強(qiáng)大的威力,它使得某些數(shù)據(jù)和函數(shù)脫離“對象”而成為“類”的一部分,正是它的這一特點(diǎn),成就了軟件的無數(shù)優(yōu)秀設(shè)計。3.動畫顯示
動畫是無所謂有,無所謂無的,靜止的畫面走的路多了,也就成了動畫。隨著時間的變更,在屏幕上顯示不同的靜止畫面,即是動畫之本質(zhì)。所以,在一個嵌入式系統(tǒng)的LCD上欲顯示動畫,必須借助定時器。沒有硬件或軟件定時器的世界是無法想像的:
(1)
沒有定時器,一個操作系統(tǒng)將無法進(jìn)行時間片的輪轉(zhuǎn),于是無法進(jìn)行多任務(wù)的調(diào)度,于是便不再成其為一個多任務(wù)操作系統(tǒng);
(2)
沒有定時器,一個多媒體播放軟件將無法運(yùn)作,因?yàn)樗恢篮螘r應(yīng)該切換到下一幀畫面;
(3)
沒有定時器,一個網(wǎng)絡(luò)協(xié)議將無法運(yùn)轉(zhuǎn),因?yàn)槠錈o法獲知何時包傳輸超時并重傳之,無法在特定的時間完成特定的任務(wù)。
因此,沒有定時器將意味著沒有操作系統(tǒng)、沒有網(wǎng)絡(luò)、沒有多媒體,這將是怎樣的黑暗?所以,合理并靈活地使用各種定時器,是對一個軟件人的最基本需求!在80186為主芯片的嵌入式系統(tǒng)中,我們需要借助硬件定時器的中斷來作為軟件定時器,在中斷發(fā)生后變更畫面的顯示內(nèi)容。在時間顯示“xx:xx”中讓冒號交替有無,每次秒中斷發(fā)生后,需調(diào)用ShowDot: void ShowDot(){ static BOOL bShowDot = TRUE;
/* 再一次領(lǐng)略static關(guān)鍵字的威力 */ if(bShowDot)
{ showChar(‘:’,xPos,yPos);} else
{ showChar(‘ ’,xPos,yPos);
} bShowDot =!bShowDot;} 4.菜單操作
無數(shù)人為之絞盡腦汁的問題終于出現(xiàn)了,在這一節(jié)里,我們將看到,在C語言中哪怕用到一丁點(diǎn)的面向?qū)ο笏枷?,軟件結(jié)構(gòu)將會有何等的改觀!筆者曾經(jīng)是個笨蛋,被菜單搞暈了,給出這樣的一個系統(tǒng): 圖1 菜單范例
要求以鍵盤上的“←→”鍵切換菜單焦點(diǎn),當(dāng)用戶在焦點(diǎn)處于某菜單時,若敲擊鍵盤上的OK、CANCEL鍵則調(diào)用該焦點(diǎn)菜單對應(yīng)之處理函數(shù)。我曾經(jīng)傻傻地這樣做著:
/* 按下OK鍵 */ void onOkKey(){ /* 判斷在什么焦點(diǎn)菜單上按下Ok鍵,調(diào)用相應(yīng)處理函數(shù) */ Switch(currentFocus){ case MENU1:
menu1OnOk();
break;case MENU2:
menu2OnOk();
break;? } } /* 按下Cancel鍵 */ void onCancelKey(){ /* 判斷在什么焦點(diǎn)菜單上按下Cancel鍵,調(diào)用相應(yīng)處理函數(shù) */ Switch(currentFocus){ case MENU1:
menu1OnCancel();
break;case MENU2:
menu2OnCancel();
break;? } } 終于有一天,我這樣做了:
/* 將菜單的屬性和操作“封裝”在一起 */ typedef struct tagSysMenu
{
char *text;
/* 菜單的文本 */
BYTE xPos;/* 菜單在LCD上的x坐標(biāo) */
BYTE yPos;/* 菜單在LCD上的y坐標(biāo) */
void(*onOkFun)();
/* 在該菜單上按下ok鍵的處理函數(shù)指針 */
void(*onCancelFun)();/* 在該菜單上按下cancel鍵的處理函數(shù)指針 */ }SysMenu, *LPSysMenu;當(dāng)我定義菜單時,只需要這樣: static SysMenu menu[MENU_NUM] = {
{
“menu1”, 0, 48, menu1OnOk, menu1OnCancel
} ,{
“ menu2”, 7, 48, menu2OnOk, menu2OnCancel
} ,{
“ menu3”, 7, 48, menu3OnOk, menu3OnCancel
} ,{
“ menu4”, 7, 48, menu4OnOk, menu4OnCancel
}
… };OK鍵和CANCEL鍵的處理變成: /* 按下OK鍵 */ void onOkKey(){
menu[currentFocusMenu].onOkFun();
} /* 按下Cancel鍵 */ void onCancelKey(){ menu[currentFocusMenu].onCancelFun();
} 程序被大大簡化了,也開始具有很好的可擴(kuò)展性!我們僅僅利用了面向?qū)ο笾械姆庋b思想,就讓程序結(jié)構(gòu)清晰,其結(jié)果是幾乎可以在無需修改程序的情況下在系統(tǒng)中添加更多的菜單,而系統(tǒng)的按鍵處理函數(shù)保持不變。面向?qū)ο?,真神了?.模擬MessageBox函數(shù)
MessageBox函數(shù),這個Windows編程中的超級猛料,不知道是多少入門者第一次用到的函數(shù)。還記得我們第一次在Windows中利用MessageBox輸出“Hello,World!”對話框時新奇的感覺嗎?無法統(tǒng)計,這個世界上究竟有多少程序員學(xué)習(xí)Windows編程是從MessageBox(“Hello,World!”,?)開始的。在我本科的學(xué)校,廣泛流傳著一個詞匯,叫做“‘Hello,World’級程序員”,意指入門級程序員,但似乎“‘Hello,World’級”這個說法更搞笑而形象。
圖2 經(jīng)典的Hello,World!圖2給出了兩種永恒經(jīng)典的Hello,World對話框,一種只具有“確定”,一種則包含“確定”、“取消”。是的,MessageBox的確有,而且也應(yīng)該有兩類!這完全是由特定的應(yīng)用需求決定的。
嵌入式系統(tǒng)中沒有給我們提供MessageBox,但是鑒于其功能強(qiáng)大,我們需要模擬之,一個模擬的MessageBox函數(shù)為:
/****************************************** /*
函數(shù)名稱:
MessageBox /*
功能說明:
彈出式對話框,顯示提醒用戶的信息 /*
參數(shù)說明:
lpStr---提醒用戶的字符串輸出信息
/*
TYPE---輸出格式(ID_OK = 0, ID_OKCANCEL = 1)/*
返回值:
返回對話框接收的鍵值,只有兩種 KEY_OK, KEY_CANCEL /****************************************** typedef enum TYPE
{ ID_OK,ID_OKCANCEL
}MSG_TYPE;extern
BYTE MessageBox(LPBYTE lpStr, BYTE TYPE){
BYTE keyValue =-1;
ClearScreen();
/* 清除屏幕 */
DisplayString(xPos,yPos,lpStr,TRUE);/* 顯示字符串 */
/* 根據(jù)對話框類型決定是否顯示確定、取消 */
switch(TYPE)
{
case
ID_OK:
DisplayString(13,yPos+High+1, “ 確定 ”, 0);
break;
case
ID_OKCANCEL:
DisplayString(8, yPos+High+1, “ 確定 ”, 0);
DisplayString(17,yPos+High+1, “ 取消 ”, 0);
break;
default:
break;
}
DrawRect(0, 0, 239, yPos+High+16+4);/* 繪制外框 */
/* MessageBox是模式對話框,阻塞運(yùn)行,等待按鍵 */
while((keyValue!= KEY_OK)||(keyValue!= KEY_CANCEL))
{ keyValue = getSysKey();} /* 返回按鍵類型 */ if(keyValue== KEY_OK){ return ID_OK;} else { return ID_CANCEL;} } 上述函數(shù)與我們平素在VC++等中使用的MessageBox是何等的神似???實(shí)現(xiàn)這個函數(shù),你會看到它在嵌入式系統(tǒng)中的妙用是無窮的。總結(jié)
本篇是本系列文章中技巧性最深的一篇,它提供了嵌入式系統(tǒng)屏幕顯示方面一些很巧妙的處理方法,靈活使用它們,我們將不再被LCD上凌亂不堪的顯示內(nèi)容所困擾。
屏幕乃嵌入式系統(tǒng)生存之重要輔助,面目可憎之顯示將另用戶逃之夭夭。屏幕編程若處理不好,將是軟件中最不系統(tǒng)、最混亂的部分,筆者曾深受其害。
C語言嵌入式系統(tǒng)編程修煉之道——鍵盤操作篇 1.處理功能鍵
功能鍵的問題在于,用戶界面并非固定的,用戶功能鍵的選擇將使屏幕畫面處于不同的顯示狀態(tài)下。例如,主畫面如圖1: 圖1 主畫面
當(dāng)用戶在設(shè)置XX上按下Enter鍵之后,畫面就切換到了設(shè)置XX的界面,如圖2:
圖2 切換到設(shè)置XX畫面
程序如何判斷用戶處于哪一畫面,并在該畫面的程序狀態(tài)下調(diào)用對應(yīng)的功能鍵處理函數(shù),而且保證良好的結(jié)構(gòu),是一個值得思考的問題。
讓我們來看看WIN32編程中用到的“窗口”概念,當(dāng)消息(message)被發(fā)送給不同窗口的時候,該窗口的消息處理函數(shù)(是一個callback函數(shù))最終被調(diào)用,而在該窗口的消息處理函數(shù)中,又根據(jù)消息的類型調(diào)用了該窗口中的對應(yīng)處理函數(shù)。通過這種方式,WIN32有效的組織了不同的窗口,并處理不同窗口情況下的消息。
我們從中學(xué)習(xí)到的就是:
(1)將不同的畫面類比為WIN32中不同的窗口,將窗口中的各種元素(菜單、按鈕等)包含在窗口之中;
(2)給各個畫面提供一個功能鍵“消息”處理函數(shù),該函數(shù)接收按鍵信息為參數(shù);
(3)在各畫面的功能鍵“消息”處理函數(shù)中,判斷按鍵類型和當(dāng)前焦點(diǎn)元素,并調(diào)用對應(yīng)元素的按鍵處理函數(shù)。
/* 將窗口元素、消息處理函數(shù)封裝在窗口中 */ struct windows {
BYTE currentFocus;
ELEMENT element[ELEMENT_NUM];
void(*messageFun)(BYTE keyValue);
… };/* 消息處理函數(shù) */ void messageFunction(BYTE keyValue){
BYTE i = 0;
/* 獲得焦點(diǎn)元素 */
while((element [i].ID!= currentFocus)&&(i < ELEMENT_NUM))
{
i++;
}
/* “消息映射” */
if(i < ELEMENT_NUM)
{
switch(keyValue)
{
case OK:
element[i].OnOk();
break;
…
}
} } 在窗口的消息處理函數(shù)中調(diào)用相應(yīng)元素按鍵函數(shù)的過程類似于“消息映射”,這是我們從WIN32編程中學(xué)習(xí)到的。編程到了一個境界,很多東西都是相通的了。其它地方的思想可以拿過來為我所用,是為編程中的“拿來主義”。
在這個例子中,如果我們還想玩得更大一點(diǎn),我們可以借鑒MFC中處理MESSAGE_MAP的方法,我們也可以學(xué)習(xí)MFC定義幾個精妙的宏來實(shí)現(xiàn)“消息映射”。2.處理數(shù)字鍵
用戶輸入數(shù)字時是一位一位輸入的,每一位的輸入都對應(yīng)著屏幕上的一個顯示位置(x坐標(biāo),y坐標(biāo))。此外,程序還需要記錄該位置輸入的值,所以有效組織用戶數(shù)字輸入的最佳方式是定義一個結(jié)構(gòu)體,將坐標(biāo)和數(shù)值捆綁在一起: /* 用戶數(shù)字輸入結(jié)構(gòu)體 */ typedef struct tagInputNum
{
BYTE byNum;/* 接收用戶輸入賦值 */
BYTE xPos;
/* 數(shù)字輸入在屏幕上的顯示位置x坐標(biāo) */
BYTE yPos;
/* 數(shù)字輸入在屏幕上的顯示位置y坐標(biāo) */
}InputNum, *LPInputNum;那么接收用戶輸入就可以定義一個結(jié)構(gòu)體數(shù)組,用數(shù)組中的各位組成一個完整的數(shù)字:
InputNum inputElement[NUM_LENGTH];/* 接收用戶數(shù)字輸入的數(shù)組 */ /* 數(shù)字按鍵處理函數(shù) */ extern void onNumKey(BYTE num){
if(num==0|| num==1)/* 只接收二進(jìn)制輸入 */
{ /* 在屏幕上顯示用戶輸入 */ DrawText(inputElement[currentElementInputPlace].xPos, inputElement[currentElementInputPlace].yPos, “%1d”, num);
/* 將輸入賦值給數(shù)組元素 */
inputElement[currentElementInputPlace].byNum = num;
/* 焦點(diǎn)及光標(biāo)右移 */
moveToRight();
} } 將數(shù)字每一位輸入的坐標(biāo)和輸入值捆綁后,在數(shù)字鍵處理函數(shù)中就可以較有結(jié)構(gòu)的組織程序,使程序顯得很緊湊。3.整理用戶輸入
繼續(xù)第2節(jié)的例子,在第2節(jié)的onNumKey函數(shù)中,只是獲取了數(shù)字的每一位,因而我們需要將其轉(zhuǎn)化為有效數(shù)據(jù),譬如要轉(zhuǎn)化為有效的XXX數(shù)據(jù),其方法是:
/* 從2進(jìn)制數(shù)據(jù)位轉(zhuǎn)化為有效數(shù)據(jù):XXX */ void convertToXXX(){
BYTE i;
XXX = 0;
for(i = 0;i < NUM_LENGTH;i++)
{
XXX += inputElement[i].byNum*power(2, NUM_LENGTH1);
}
} 反之,我們也可能需要在屏幕上顯示那些有效的數(shù)據(jù)位,因?yàn)槲覀円残枰軌蚍聪蜣D(zhuǎn)化:
/* 從有效數(shù)據(jù)轉(zhuǎn)化為2進(jìn)制數(shù)據(jù)位:XXX */ void convertFromXXX(){
BYTE i;
XXX = 0;
for(i = 0;i < NUM_LENGTH;i++)
{
inputElement[i].byNum = XXX / power(2, NUM_LENGTH1)% 2;
}
} 當(dāng)然在上面的例子中,因?yàn)閿?shù)據(jù)是2進(jìn)制的,用power函數(shù)不是很好的選擇,直接用“<< >>”移位操作效率更高,我們僅是為了說明問題的方便。試想,如果用戶輸入是十進(jìn)制的,power函數(shù)或許是唯一的選擇了。總結(jié)
本篇給出了鍵盤操作所涉及的各個方面:功能鍵處理、數(shù)字鍵處理及用戶輸入整理,基本上提供了一個全套的按鍵處理方案。對于功能鍵處理方法,將LCD屏幕與Windows窗口進(jìn)行類比,提出了較新穎地解決屏幕、鍵盤繁雜交互問題的方案。
計算機(jī)學(xué)的許多知識都具有相通性,因而,不斷追趕時髦技術(shù)而忽略基本功的做法是徒勞無意的。我們最多需要“精通”三種語言(精通,一個在如今的求職簡歷里泛濫成災(zāi)的詞語),最佳拍檔是匯編、C、C++(或JAVA),很顯然,如果你“精通”了這三種語言,其它語言你應(yīng)該是可以很快“熟悉”的,否則你就沒有“精通”它們。
C語言嵌入式系統(tǒng)編程修煉之道——性能優(yōu)化篇 1.使用宏定義
在C語言中,宏是產(chǎn)生內(nèi)嵌代碼的唯一方法。對于嵌入式系統(tǒng)而言,為了能達(dá)到性能要求,宏是一種很好的代替函數(shù)的方法。
寫一個“標(biāo)準(zhǔn)”宏MIN,這個宏輸入兩個參數(shù)并返回較小的一個:
錯誤做法:
#define MIN(A,B)(A <= B ? A : B)正確做法:
#define MIN(A,B)((A)<=(B)?(A):(B))對于宏,我們需要知道三點(diǎn):(1)宏定義“像”函數(shù);
(2)宏定義不是函數(shù),因而需要括上所有“參數(shù)”;(3)宏定義可能產(chǎn)生副作用。下面的代碼:
least = MIN(*p++, b);將被替換為:
((*p++)<=(b)?(*p++):(b))發(fā)生的事情無法預(yù)料。
因而不要給宏定義傳入有副作用的“參數(shù)”。2.使用寄存器變量
當(dāng)對一個變量頻繁被讀寫時,需要反復(fù)訪問內(nèi)存,從而花費(fèi)大量的存取時間。為此,C語言提供了一種變量,即寄存器變量。這種變量存放在CPU的寄存器中,使用時,不需要訪問內(nèi)存,而直接從寄存器中讀寫,從而提高效率。寄存器變量的說明符是register。對于循環(huán)次數(shù)較多的循環(huán)控制變量及循環(huán)體內(nèi)反復(fù)使用的變量均可定義為寄存器變量,而循環(huán)計數(shù)是應(yīng)用寄存器變量的最好候選者。(1)
只有局部自動變量和形參才可以定義為寄存器變量。因?yàn)榧拇嫫髯兞繉儆趧討B(tài)存儲方式,凡需要采用靜態(tài)存儲方式的量都不能定義為寄存器變量,包括:模塊間全局變量、模塊內(nèi)全局變量、局部static變量;
(2)
register是一個“建議”型關(guān)鍵字,意指程序建議該變量放在寄存器中,但最終該變量可能因?yàn)闂l件不滿足并未成為寄存器變量,而是被放在了存儲器中,但編譯器中并不報錯(在C++語言中有另一個“建議”型關(guān)鍵字:inline)。
下面是一個采用寄存器變量的例子: /* 求1+2+3+?.+n的值 */ WORD Addition(BYTE n){ register i,s=0;for(i=1;i<=n;i++){ s=s+i;} return s;} 本程序循環(huán)n次,i和s都被頻繁使用,因此可定義為寄存器變量。3.內(nèi)嵌匯編
程序中對時間要求苛刻的部分可以用內(nèi)嵌匯編來重寫,以帶來速度上的顯著提高。但是,開發(fā)和測試匯編代碼是一件辛苦的工作,它將花費(fèi)更長的時間,因而要慎重選擇要用匯編的部分。
在程序中,存在一個80-20原則,即20%的程序消耗了80%的運(yùn)行時間,因而我們要改進(jìn)效率,最主要是考慮改進(jìn)那20%的代碼。
嵌入式C程序中主要使用在線匯編,即在C程序中直接插入_asm{ }內(nèi)嵌匯編語句:
/* 把兩個輸入?yún)?shù)的值相加,結(jié)果存放到另外一個全局變量中 */ int result;
void Add(long a, long *b)
{
_asm
{
MOV
AX, a
MOV
BX, b
ADD
AX, [BX]
MOV
result, AX
}
}
4.利用硬件特性
首先要明白CPU對各種存儲器的訪問速度,基本上是:
CPU內(nèi)部RAM > 外部同步RAM > 外部異步RAM > FLASH/ROM 對于程序代碼,已經(jīng)被燒錄在FLASH或ROM中,我們可以讓CPU直接從其中讀取代碼執(zhí)行,但通常這不是一個好辦法,我們最好在系統(tǒng)啟動后將FLASH或ROM中的目標(biāo)代碼拷貝入RAM中后再執(zhí)行以提高取指令速度; 對于UART等設(shè)備,其內(nèi)部有一定容量的接收BUFFER,我們應(yīng)盡量在BUFFER被占滿后再向CPU提出中斷。例如計算機(jī)終端在向目標(biāo)機(jī)通過RS-232傳遞數(shù)據(jù)時,不宜設(shè)置UART只接收到一個BYTE就向CPU提中斷,從而無謂浪費(fèi)中斷處理時間;
如果對某設(shè)備能采取DMA方式讀取,就采用DMA讀取,DMA讀取方式在讀取目標(biāo)中包含的存儲信息較大時效率較高,其數(shù)據(jù)傳輸?shù)幕締挝皇菈K,而所傳輸?shù)臄?shù)據(jù)是從設(shè)備直接送入內(nèi)存的(或者相反)。DMA方式較之中斷驅(qū)動方式,減少了CPU 對外設(shè)的干預(yù),進(jìn)一步提高了CPU與外設(shè)的并行操作程度。5.活用位操作
使用C語言的位操作可以減少除法和取模的運(yùn)算。在計算機(jī)程序中數(shù)據(jù)的位是可以操作的最小數(shù)據(jù)單位,理論上可以用“位運(yùn)算”來完成所有的運(yùn)算和操作,因而,靈活的位操作可以有效地提高程序運(yùn)行的效率。舉例如下: /* 方法1 */ int i,j;i = 879 / 16;j = 562 % 32;
/* 方法2 */ int i,j;i = 879 >> 4;j = 562-(562 >> 5 << 5);對于以2的指數(shù)次方為“*”、“/”或“%”因子的數(shù)學(xué)運(yùn)算,轉(zhuǎn)化為移位運(yùn)算“<< >>”通??梢蕴岣咚惴ㄐ?。因?yàn)槌顺\(yùn)算指令周期通常比移位運(yùn)算大。
C語言位運(yùn)算除了可以提高運(yùn)算效率外,在嵌入式系統(tǒng)的編程中,它的另一個最典型的應(yīng)用,而且十分廣泛地正在被使用著的是位間的與(&)、或(|)、非(~)操作,這跟嵌入式系統(tǒng)的編程特點(diǎn)有很大關(guān)系。我們通常要對硬件寄存器進(jìn)行位設(shè)置,譬如,我們通過將AM186ER型80186處理器的中斷屏蔽控制寄存器的第低6位設(shè)置為0(開中斷2),最通用的做法是: #define INT_I2_MASK
0x0040
wTemp = inword(INT_MASK);outword(INT_MASK, wTemp &~INT_I2_MASK);而將該位設(shè)置為1的做法是:
#define INT_I2_MASK
0x0040
wTemp = inword(INT_MASK);outword(INT_MASK, wTemp | INT_I2_MASK);判斷該位是否為1的做法是:
#define INT_I2_MASK
0x0040
wTemp = inword(INT_MASK);if(wTemp & INT_I2_MASK){
?
/* 該位為1 */ } 上述方法在嵌入式系統(tǒng)的編程中是非常常見的,我們需要牢固掌握。總結(jié)
在性能優(yōu)化方面永遠(yuǎn)注意80-20準(zhǔn)備,不要優(yōu)化程序中開銷不大的那80%,這是勞而無功的。
宏定義是C語言中實(shí)現(xiàn)類似函數(shù)功能而又不具函數(shù)調(diào)用和返回開銷的較好方法,但宏在本質(zhì)上不是函數(shù),因而要防止宏展開后出現(xiàn)不可預(yù)料的結(jié)果,對宏的定義和使用要慎而處之。很遺憾,標(biāo)準(zhǔn)C至今沒有包括C++中inline函數(shù)的功能,inline函數(shù)兼具無調(diào)用開銷和安全的優(yōu)點(diǎn)。
使用寄存器變量、內(nèi)嵌匯編和活用位操作也是提高程序效率的有效方法。除了編程上的技巧外,為提高系統(tǒng)的運(yùn)行效率,我們通常也需要最大可能地利用各種硬件設(shè)備自身的特點(diǎn)來減小其運(yùn)轉(zhuǎn)開銷,例如減小中斷次數(shù)、利用DMA傳輸方式等。