久久99精品久久久久久琪琪,久久人人爽人人爽人人片亞洲,熟妇人妻无码中文字幕,亚洲精品无码久久久久久久

Java系統程序員修煉之道

時間:2019-05-14 16:12:29下載本文作者:會員上傳
簡介:寫寫幫文庫小編為你整理了多篇相關的《Java系統程序員修煉之道》,但愿對你工作學習有幫助,當然你在寫寫幫文庫還可以找到更多《Java系統程序員修煉之道》。

第一篇:Java系統程序員修煉之道

Java系統程序員修煉之道

——動力節點java 一:Java語言學習

對線程(thread),串行化,反射,網絡編程,JNI技術,容器(Map,List, Iterator), 類加載器(ClassLoader),輸入輸出流,垃圾回收機制,有比較深入的了解,最起碼做過項目應用。有過Java項目的性能優化經驗,最起碼掌握一種性能監視工具的使用,熟悉JVM參數,最起碼知道可以在JVM啟動時指定不同垃圾回收機制,以及不同垃圾回收機制之間的差別,熟悉JVM參數優化。二:J2EE方面

最好知道JDBC規范是怎么回事情,面對Oracle數據庫如果告訴你JDBC驅動不能用了,你還知道有OCI驅動可以。掌握常見的SQL語句,熟悉JMS,JNDI等組件,掌握一套web開發模式,從前臺到后臺,有能力整合好這樣的框架。理解并掌握MVC思想,像SSH已經實現了MVC的分層,幾乎不需要你自己再實現,假設你開發一個簡單的Swing程序,你能MVC就說明你真的掌握了MVC的精髓。有能力在J2EE前端開發中構建自己的MVC模式,知道什么是WEB2.0,知道什么是SOA,SaaS,SaaP等含義 三:理解并能合理運用設計模式,UML建模

知道并理解設計模式中蘊含的幾種基本原則如:里氏替換原則,開閉原則,合成復用原則,依賴倒置原則有很好的理解,并能舉例說明。對常用的設計模式如工廠模式,單例模式,觀察者模式,責任鏈模式,橋接模式等知道靈活運用,明白什么是回調(Callback)。最后用一位高人話來總結設計模式,它是為了讓軟件更容易被別人讀懂,更容易維護而產生,設計模式本質是程序員之間的交流,如果A用工廠模式設計一個模塊B來接替,A只要說該模塊是工廠模式實現,B維護起來應該容易得多,所以設計模式是關于交流,不關于代碼。切忌濫用設計模式。學會使用UML建模工具至少熟悉一種URL建模工具。四:注重用戶體驗,掌握KISS原則,知道歐卡姆剃刀原則

顧客就是上帝這個口號我們已經喊了N年了,程序員的勞動成果最終也需要轉換為服務提供給客戶,用戶體驗至關重要,常常看到的場景是功能實現了,軟件很難使用,程序員有個很充足的理由我不是美工,其實注重用戶體驗跟美工八桿子也打不到一起,FoxMail的成功在很大程度是用戶體驗的成功,友好,清晰的用戶提示,強的容錯與糾錯設計是獲得好的用戶體驗的不二法門。傻瓜相機顧名思義傻子都會使用,這個就著名的KISS原則(Keep itsimple and stupid)意思是UI設計要簡單明了,傻子一看就知道怎么用,想想我們做出來的東西,對照說明書都不知道怎么用。另外一個就是最著名的例子IPhone手機外觀設計,是典型的歐卡姆剃刀設計原則來完成人機交互。五:自動測試與軟件配置管理(SCM)實現

知道什么是軟件配置管理,知道Hudson運用該工具SCM,知道怎么獲取測試代碼覆蓋率,Java有效代碼行數(NCSS),完成firebug,JDepend等工具集成ant/maven。熟悉并注重在開發過程中使用JUnit單元測試,理解白盒測試規范。六:熟悉常見的網絡通信協議

對HTTP協議,知道POST, GET的區別是什么,閱讀過HTTP相關的RFC文檔。學會使用sniffer工具查看數據包,幫助查找與調試程序,知道TCP與UDP的區別,知道并理解E-Mail發送與接受的協議如SMTP,POP3,IMAP等協議,了解MIME與Base64編碼。知道組播是怎么回事情。

七:面向市場,永遠對新技術保持渴望

計算機技術的發展日新月異,做為IT行業的軟件開發人員要不斷的給自己充電,更新自己的技術與時代保持同步,同時還要面向市場,華為總裁任正非說過-“華為的技術革新必須面向市場”,作為程序員同樣要有市場意識,很多人都后悔沒有在android剛出來的時候加以關注學習。那些很早關注android開發技術的很多程序員因此獲得豐厚回報。如今HTML5得到越來越多的瀏覽器廠家支持,你是否已經跟上腳步,開始學習。八:保持謙虛,三人行必有我師

喬幫主說他要保持初心,努力學習,我等更應該保持謙虛,IT技術發展日新月異,在你眼中不可能實現的技術,也許別人早已經有思路。保持謙虛就有機會吸取別人身上的長處,古人有云:滿招損,謙受益。一個得道的高人更是說出了”下下人,上上智”的禪語。永遠不要拒絕幫助你周圍的人解決難題,解決難題是進步最快途徑。不要放棄任何一次可以提升自己技術與能力的機會。

九:養成總結的習慣,不斷反思

上學的時候老師常讓寫小結,也沒總結出來所以然,以至于工作以后再也不提這檔子事情,建議每個項目做完以后對自己都有個小結,總結自己在項目里面學到了什么,反問自己能不能完成在不需要別人幫助的情況下自己完成這樣的系統搭建,是否熟悉與掌握項目中所用到的技術,即使有些東西不是你負責完成的但是什么也不能阻擋一顆求知的心,總結要盡量詳細記錄你遇到那些難題是怎么一個一個的解決的,下次再遇到你是否可以很快解決或者避免這樣的問題。有總結才有提高,孔子曰:學而不思則罔,如果我們只是coding到吐血,不思考,不總結提高,永遠不可能有能有本質提高,秦相李斯有云:“泰山不讓土壤,故能成其大,河海不擇細流,故能就其深”,點滴積累不斷總結方能量變導致質變。十:數學功底與算法知識 用任何編程語言開發應用,都離不開核心算法支持,很多國外的軟件單單從UI上看,恐怕寫幾年程序的人都可以模仿,但是UI之下的那些真實深淺不一,相信不是你想模仿就可以模仿的,為什么我們越來越山寨,因為我們沒有核心競爭力,對于程序員來說算法與數學顯然是他最重要的核心競爭力之一。《算法導論》,《編程珠璣》等書絕對值得讀十遍。微軟亞洲研究院視覺計算組負責人在一次演講中說到他們招人的標準是“三好學生– 數學好,編程好,態度好”。可是現實的普遍情況卻是-微機原理鬧危機,匯編語言不會變,實變函數學十遍。計算機基礎知識被大家普遍忽視。從今天開始好好學習吧…… 十一:Java代碼反編譯與代碼保護

Java編譯產生字節碼,因而可以被輕松的逆向工程(反編譯),微軟的C#生產的DLL也一樣可以被輕松反編譯。正式由于這個原因產生了許多Java開源的代碼保護工具,而Proguar是其中佼佼者,已經被google集成在android之中用于Java代碼保護 十二:努力成為某個行業或者領域骨干

面對漫長的職業生涯,要想不被淘汰,必須具備一招鮮吃遍天下的能力,選擇自己感興趣的方向,努力而深入的研究,計算機技術發展到今天已經細分很細,努力研究一種Java開源框架或者開源HTTP服務器源碼或者研究過網絡爬蟲源碼或者WEBKIT內核,不愁沒有人要你。如果你是非常了解金融,企業ERP,證券,保險,移動應用行業的應用開發業務的人,一樣不用愁工作。這些知識不隨語言而改變,努力做一個有核心競爭力的Java程序員。十三:提高語言與書面表達能力,掌握基礎的項目管理知識

文檔與語言表達能力是最好的向外界展現自己能力的方式,很多程序員編程能力很高,表達能力一般,Linux能夠成功,除了歸功于網絡社區的力量之外,也得益于Linux作者本人給各大基金會寫信,宣傳推廣,試想如果沒有良好的書面語言表達能力,即使Linux系統再優秀,卻無法被準確表達,失去各大基金會的支持,Linux還會像今天這么好的局面嘛。所以重視文檔,重視提升溝通與表達能力,才有可能成為Java系統程序員。掌握基本的2/8原則,學會將模塊細化分配給不同的人,預見并控制項目風險,把握項目進度,優化流程,合理的時間管理,了解TDD,熟悉敏捷開發模式,常規軟件開發模式。

第二篇:Java程序員修煉之道

從2002開始接觸Java學會HelloWorld這么經典的程序到如今不知不覺已經十年啦,十年中

親耳聽到過不少大牛的演講,見到過項目中的神人在鍵盤上運指如飛的編程速度,當時就

被震撼了。當編程越來越成體力活,我們還能有自己的思想,還能修煉為Java系統級別的

程序員嘛?學習與修煉以下知識與技能,幫你早日達成愿望。

一:Java語言學習

對線程(thread),串行化,反射,網絡編程,JNI技術,容器(Map,List, Iterator), 類加載器

(ClassLoader),輸入輸出流,垃圾回收機制,有比較深入的了解,最起碼做過項目應用。有

過Java項目的性能優化經驗,最起碼掌握一種性能監視工具的使用,熟悉JVM參數,最起

碼知道可以在JVM啟動時指定不同垃圾回收機制,以及不同垃圾回收機制之間的

差別,熟悉JVM參數優化。

二:J2EE方面

最好知道JDBC規范是怎么回事情,面對Oracle數據庫如果告訴你JDBC驅動不能用了,你

還知道有OCI驅動可以。掌握常見的SQL語句,熟悉JMS,JNDI等組件,掌握一套web開

發模式,從前臺到后臺,有能力整合好這樣的框架。理解并掌握MVC思想,像SSH已經實

現了MVC的分層,幾乎不需要你自己再實現,假設你開發一個簡單的Swing程序,你能MVC

就說明你真的掌握了MVC的精髓。有能力在J2EE前端開發中構建自己的MVC模式,知道

什么是WEB2.0,知道什么是SOA,SaaS,SaaP等含義

三:理解并能合理運用設計模式,UML建模

知道并理解設計模式中蘊含的幾種基本原則如:里氏替換原則,開閉原則,合成復用原則,依賴倒置原則有很好的理解,并能舉例說明。對常用的設計模式如工廠模式,單例模式,觀

察者模式,責任鏈模式,橋接模式等知道靈活運用,明白什么是回調(Callback)。最后用一位

高人話來總結設計模式,它是為了讓軟件更容易被別人讀懂,更容易維護而產生,設計模

式本質是程序員之間的交流,如果A用工廠模式設計一個模塊B來接替,A只要說該模塊是

工廠模式實現,B維護起來應該容易得多,所以設計模式是關于交流,不關于代碼。切忌濫

用設計模式。學會使用UML建模工具至少熟悉一種URL建模工具。

四:注重用戶體驗,掌握KISS原則,知道歐卡姆剃刀原則

顧客就是上帝這個口號我們已經喊了N年了,程序員的勞動成果最終也需要轉換為服務提

供給客戶,用戶體驗至關重要,常常看到的場景是功能實現了,軟件很難使用,程序員有個

很充足的理由我不是美工,其實注重用戶體驗跟美工八桿子也打不到一起,FoxMail的成功

在很大程度是用戶體驗的成功,友好,清晰的用戶提示,強的容錯與糾錯設計是獲得好的

用戶體驗的不二法門。傻瓜相機顧名思義傻子都會使用,這個就著名的KISS原則(Keep it

simple and stupid)意思是UI設計要簡單明了,傻子一看就知道怎么用,想想我們做出來的

東西,對照說明書都不知道怎么用。另外一個就是最著名的例子IPhone手機外觀設計,是 典型的歐卡姆剃刀設計原則來完成人機交互。

五:自動測試與軟件配置管理(SCM)實現

知道什么是軟件配置管理,知道Hudson微機原理鬧危機,匯編語言不會變,實變函數學

十遍。計算機基礎知識被大家普遍忽視。從今天開始好好學習吧……

十一:Java代碼反編譯與代碼保護

Java編譯產生字節碼,因而可以被輕松的逆向工程(反編譯),微軟的C#生產的DLL也一樣可

以被輕松反編譯。正式由于這個原因產生了許多Java開源的代碼保護工具,而Proguard是

其中佼佼者,已經被google集成在android之中用于Java代碼保護,訪問這里了解更多:

http://proguard.sourceforge.net/

十二:努力成為某個行業或者領域骨干

面對漫長的職業生涯,要想不被淘汰,必須具備一招鮮吃遍天下的能力,選擇自己感興趣的

方向,努力而深入的研究,計算機技術發展到今天已經細分很細,努力研究一種Java開源

框架或者開源HTTP服務器源碼或者研究過網絡爬蟲源碼或者WEBKIT內核,不愁沒有人要

你。如果你是非常了解金融,企業ERP,證券,保險,移動應用行業的應用開發業務的人,一樣不用愁工作。這些知識不隨語言而改變,努力做一個有核心競爭力的Java程序員。

十三:提高語言與書面表達能力,掌握基礎的項目管理知識

文檔與語言表達能力是最好的向外界展現自己能力的方式,很多程序員編程能力很高,表達

能力一般,Linux能夠成功,除了歸功于網絡社區的力量之外,也得益于Linux作者本人給各

大基金會寫信,宣傳推廣,試想如果沒有良好的書面語言表達能力,即使Linux系統再優秀,卻無法被準確表達,失去各大基金會的支持,Linux還會像今天這么好的局面嘛。所以重視

文檔,重視提升溝通與表達能力,才有可能成為Java系統程序員。掌握基本的2/8原則,學

會將模塊細化分配給不同的人,預見并控制項目風險,把握項目進度,優化流程,合理的時

間管理,了解TDD,熟悉敏捷開發模式,常規軟件開發模式。

十四:掌握英語,良好的讀寫能力

英語是計算機的母語,掌握好英語對于閱讀英文資料學習新技術大有幫助,我的建議是盡量

讀英文原版書,如果是算法方面的可能會困難一點,但是其它像設計模式,軟件工程,OO

編程思想等盡量讀原版,提高自己的英文水平,多多訪問開發者,code project,程序員天堂,Pc-magazine等英文IT網站。英語絕對是你必須修煉與提高的技能。此外英語好在外資企業

尤其重要,只有外語足夠好才可能在外資企業中突破職業瓶頸,向上發展。

第三篇:Java程序員修煉十大過程

Java程序員修煉十大過程

學習java這么久,見到過項目中的神人在鍵盤上運指如飛的編程速度,當時就被震撼了。當編程越來越成體力活,我們還能有自己的思想,還能修煉為Java系統級別的程序員嘛?學習與修煉以下知識與技能,幫你早日達成愿望。

一、努力成為某個行業或者領域骨干

面對漫長的職業生涯,要想不被淘汰,必須具備一招鮮吃遍天下的能力,選擇自己感興趣的方向,努力而深入的研究,計算機技術發展到今天已經細分很細,努力研究一種Java開源框架或者開源HTTP服務器源碼或者研究過網絡爬蟲源碼或者WEBKIT內核,不愁沒有人要你。如果你是非常了解金融,企業ERP,證券,保險,移動應用行業的應用開發業務的人,一樣不用愁工作。這些知識不隨語言而改變,努力做一個有核心競爭力的Java程序員。

二、保持謙虛,三人行必有我師

喬幫主說他要保持初心,努力學習,我等更應該保持謙虛,IT技術發展日新月異,在你眼中不可能實現的技術,也許別人早已經有思路。保持謙虛就有機會吸取別人身上的長處,古人有云:滿招損,謙受益。一個得道的高人更是說出了“下下人,上上智”的禪語。永遠不要拒絕幫助你周圍的人解決難題,解決難題是進步最快途徑。不要放棄任何一次可以提升自己技術與能力的機會。

三、熟悉常見的網絡通信協議

對HTTP協議,知道POST, GET的區別是什么,閱讀過HTTP相關的RFC文檔。學會使用sniffer工具查看數據包,幫助查找與調試程序,知道TCP與UDP的區別,知道并理解E-Mail發送與接受的協議如SMTP,POP3,IMAP等協議,了解MIME與Base64編碼。知道組播是怎么回事情。

四、理解并能合理運用設計模式,UML建模

知道并理解設計模式中蘊含的幾種基本原則如:里氏替換原則,開閉原則,合成復用原則,依賴倒置原則有很好的理解,并能舉例說明。對常用的設計模式如工廠模式,單例模式,觀察者模式,責任鏈模式,橋接模式等知道靈活運用,明白什么是回調(Callback)。最后用一位高人話來總結設計模式,它是為了讓軟件更容易被別人讀懂,更容易維護而產生,設計模式本質是程序員之間的交流,如果A用工廠模式設計一個模塊B來接替,A只要說該模塊是工廠模式實現,B維護起來應該容易得多,所以設計模式是關于交流,不關于代碼。切忌濫用設計模式。學會使用UML建模工具至少熟悉一種URL建模工具。

五、自動測試與軟件配置管理(SCM)實現

知道什么是軟件配置管理,知道Hudson-http://java.net/projects/hudson/運用該工具SCM,知道怎么獲取測試代碼覆蓋率,Java有效代碼行數(NCSS),完成firebug,JDepend等工具集成ant/maven.熟悉并注重在開發過程中使用JUnit單元測試,理解白盒測試規范。

六、Java語言學習

對線程(thread),串行化,反射,網絡編程,JNI技術,容器(Map,List, Iterator),類加載器(ClassLoader),輸入輸出流,垃圾回收機制,有比較深入的了解,最起碼做過項目應用。有過Java項目的性能優化經驗,最起碼掌握一種性能監視工具的使用,熟悉JVM參數,最起碼知道可以在JVM啟動時指定不同垃圾回收機制,以及不同垃圾回收機制之間的差別,熟悉JVM參數優化。

七、掌握英語,良好的讀寫能力

英語是計算機的母語,掌握好英語對于閱讀英文資料學習新技術大有幫助,我的建議是盡量讀英

文原版書,如果是算法方面的可能會困難一點,但是其它像設計模式,軟件工程,OO編程思想等盡量讀原版,提高自己的英文水平,多多訪問開發者,code project,程序員天堂,Pc-magazine等英文IT網站。英語絕對是你必須修煉與提高的技能。此外英語好在外資企業尤其重要,只有外語足夠好才可能在外資企業中突破職業瓶頸,向上發展。

八、養成總結的習慣,不斷反思

上學的時候老師常讓寫小結,也沒總結出來所以然,以至于工作以后再也不提這檔子事情,建議每個項目做完以后對自己都有個小結,總結自己在項目里面學到了什么,反問自己能不能完成在不需要別人幫助的情況下自己完成這樣的系統搭建,是否熟悉與掌握項目中所用到的技術,即使有些東西不是你負責完成的但是什么也不能阻擋一顆求知的心,總結要盡量詳細記錄你遇到那些難題是怎么一個一個的解決的,下次再遇到你是否可以很快解決或者避免這樣的問題。有總結才有提高,孔子曰:學而不思則罔,如果我們只是coding到吐血,不思考,不總結提高,永遠不可能有能有本質提高,秦相李斯有云:“泰山不讓土壤,故能成其大,河海不擇細流,故能就其深”,點滴積累不斷總結方能量變導致質變。

九、Java代碼反編譯與代碼保護

Java編譯產生字節碼,因而可以被輕松的逆向工程(反編譯),微軟的C#生產的DLL也一樣可以被輕松反編譯。正式由于這個原因產生了許多Java開源的代碼保護工具,而Proguard是其中佼佼者,已經被google集成在android之中用于Java代碼保護。

十、面向市場,永遠對新技術保持渴望

計算機技術的發展日新月異,做為IT行業的軟件開發人員要不斷的給自己充電,更新自己的技術與時代保持同步,同時還要面向市場,華為總裁任正非說過-“華為的技術革新必須面向市場”,作為程序員同樣要有市場意識,很多人都后悔沒有在android剛出來的時候加以關注學習。那些很早關注android開發技術的很多程序員因此獲得豐厚回報。如今HTML5得到越來越多的瀏覽器廠家

支持,你是否已經跟上腳步,開始學習。

第四篇:程序員修煉 收藏

程序員修煉 收藏

程序就是一系列按步驟進行的操作序列,它有好多種級別,比如最低級的微程序、次低級的匯編程序、高級的各種編程語言程序、最高級的腳本語言程序,也許我列的不對,但沒關系,我要說的是不管是那個級別的程序,其本質都是操作的邏輯序列。大多數系統和應用程序都是建立在高級編程語言上的,比如C、C++、C#、FORTRAN、BISIC、JAVA等等,就讓我們只關注這一級的編程能力吧。因此如果一個程序員的邏輯能力不高,他永遠都不能成為一名具有合格職業水準的程序員,我們在下面的討論有關編程能力的方方面面,最終都是為了最大程度地提高和實現一名程序員的邏輯能力。

一、掌握基礎知識:十六年寒窗的持續積累

從7歲讀小學起,經過16年的學習,你從軟件專業本科畢業后,必須完成以下幾門專業課程的學習:計算機組成、操作系統原理、匯編語言、數據結構、編譯原理、數據庫原理、軟件工程、結構性設計語言(PASCAL、C)、面向對象設計語言(C++、C#)、計算機網絡等,你最好還懂一些算法分析、分布式系統、計算機圖形學、形式邏輯、人工智能原理、軟件設計模式、軟件構架/框架等研究生的課程,16年來,你積累的除了知識,更重要的是形成最適合自己的學習方法和工作方法。這些是你具備程序員職業水準的基礎能力,不要受什么計算機軟件怪杰之類傳奇的影響,那不過是小概率事件,而且這些怪杰們就算沒有讀過軟件本科和研究生,也往往自學了大多數專業課程,很可能比在校學習的學生對這些課程的精髓部分理解的更好,還有他們的工作方法和思維方式是特別而高效的,但普遍性差,可以借鑒,不宜模仿。好,所以現在你只需要問問自己,那些課程和知識都學會并掌握了嗎?如果是,那就準備好進行實踐了。

二、在實踐中提高:成為一名高水平的Coder

好了,你畢業了,在校功課都不錯,也找了一個專業對口的工作,你想大展鴻圖了,可是別急,你的翅膀還不夠硬,不信我們說來看看。

通常,你在工作中都會用到某一種單位/公司固定的操作系統和編程語言開發環境,比如Windows、UNIX、LINUX等操作系統,又比如用VC、VB、PB、Delph、JAVA、Motif/XWindow、QT、OpenGL、OpenInventor等編程語言和開發環境,我們在后面把它們合稱為開發環境。就在校學習的有關開發環境的知識而言,大概你距工作需要的差距是不小的,當某個操作系統和編程語言環境成為你的飯碗時,就不應也不能用通過課程/認證考試之類的眼光和要求來評價你的能力,即使你能考100分。你需要深入地學習該操作系統和編程語言環境的各類開發手冊的所有內容,你會說大多數你都用不上,其實你既對又不對,對的是單從使用的角度而言,你確實用不上開發手冊的大多數內容,比如龐大的VC開發類庫和復雜的開發環境,你在實際工作中能用到的不到總數的1/10或1/5,不對的地方在于,你用到的部分不是孤立存在的,它們是整個體系中的一部分,只有對整個體系有了一個較完整的了解,才能得心應手、隨心所欲地用好你用到的部分,你才算初步具備在這種開發環境下進行Coding的職業水準(還遠不夠程序員的職業水準呢),而這只是剛開始。如何才能真正掌握一種開發環境的全面的知識呢,最原始的辦法就是讀開發指南/教程、參考手冊,一般來講,學習開發指南/教程時,你如果是一個認真的人,都會完成5/10~7/10左右內容的學習和練習,如果你想成為職業選手,就應該完成9/10以上內容的學習和練習。參考手冊不同,大多數所謂的“程序員”們只是用到了才翻翻,這差的太遠了,你應該象讀開發指南/教程一樣,每個環節都要讀,比如VC,參考手冊中的每個類,類的每個函數,都要讀上幾遍,它們往往是一小伙一小伙地糾纏在一起使用的,開始時讀得你毫無頭緒、心煩意亂,不要緊,還有一手呢,如果你開發環境安裝的全面,它們往往都有開發商做的demo例子可看,你就進入另一個境界了,開始時你關注demo中的具體技術,后來你發現這些demo的程序寫的都還算不錯,結構簡單但合理,如果你真的用心,就一定能發現一些個別的demo是極品,它所展現的程序邏輯結構是你設計不出來的,你現在有點更關心它的程序設計構架,甚于對你原始目的(某種相關的技術/技巧)的關注,這時的你,開始了從一名Coder向一名Programmer的轉變,你會忍不住要看看開發商提供的源程序,比如.h和.cpp,通常你會找到include路徑下所有的.h程序,你才知道,哇!好多好多東東在參考手冊中都沒提到,你要學的太多了,沒時間顧及其它的業余愛好了,現在知道為什么程序員是年輕人的職業了吧,你要有足夠多的時間才行,即使你的智商有160。如果你走到這一步,在你工作的團隊中,已經是經常有人向你請教技術問題,經常有人請求你幫忙debug,你已是公認的“高手”了,別得意,因為你仍然是個Coder,為什么這么說呢,你想想,你已深入了解了這個開發環境中的各種技能,知道一名Coder如何用好這些東西,可是你能設計的出提供給Coder們用的東西嗎?唔??,你想了想,可能還不太行。對了,就是這樣,你還是一名小我境界的程序員呢,本質是個Coder,當然已是一名高水平的Coder了,然而你需要進一步登堂入室才能成為一名真正的程序員。

讓我們繼續吧,通常你都是從精通一種編程環境開始的,假設你已經較為精通在Windows下用VC開發軟件了,這時在技術和技巧方面你將面臨一小一大兩個挑戰,第一個小挑戰是如果公司/單位改換了開發環境,比如用LINUX下的QT交互語言工具進行開發,你不過是把前面掌握VC的過程再來一遍,由于在主觀上經歷了VC工具的學習過程,在客觀上各種開發環境都有太多相似的方面,這回你掌握的應該較快。要小心,在這時第一次誘惑之門打開了,因為你感覺良好,看!這回這么快,我就這么好地掌握了新的開發環境,你開始關注其它暫時還用不到的同類環境,比如VB、Delph、JAVA,如饑似渴地掌握各種開發工具,證明自己的學習能力和價值,但你忘了一點,你仍然是個Coder,只不過是一個在好多開發環境下都能編程的Coder,就像你生活在中國,因而精通了漢語,工作需要你又掌握了英語,然后你就來了勁,把俄語、日語、阿拉伯語、拉丁語,等等等等,都學習個遍,我只能說,有點BT。你忘了自己是個職業人,同一類的東西工作中用得到才需學習,太多太多的Coder們喜歡在一起比較和炫耀自己會掌握了幾種開發工具,不信你看看招聘時的求職書就知道了,sigh!他們中絕大多數人永遠都只能停留在這個層次上,心浮氣躁,一生都再也當不成真正的程序員了。總結一下,其實你在這時需要的是對自己掌握新開發環境的能力的自信,而不是一遍遍地重復來證明自己。第二個大挑戰就是你明白了只掌握VC是不夠的,你發現自己有點淺薄,有很多東東你會用但你不太懂,很多方面支持VC編程的知識你都沒掌握,比如操作系統的源碼、網絡協議知識、Windows 的注冊表、進程和線程的基礎知識、硬件驅動方面的知識、ActiveX、Windows 龐大的 API,又是一個等等等等,這些基礎知識的學習和掌握可是要花費大量時間的,你再一次深切地感到時間太不夠用了,因為這時的你大概有許多俗務纏身了,所以有點沮喪,還不用提IT業每天不知有多少新東西在發布,KAO,永遠都跟不上,越拉越遠了。哎!別氣餒,振作一點,你還是忘記了自己是個職業人,既然好多東東在工作中你永遠都沒機會用,那么干嘛要學呢?用什么才學什么,最多預測到馬上要用什么,先一步學什么好了,要知道沒有人是真正的、無所不精的全科大夫,除非你是神,但如果你還在耐著性子看這篇文章,你肯定是個人嘛。

OK,一般工作后三五年,你經歷了上述過程,經受了誘惑和考驗,終于明白了一個道理:你要的是強勁的學習知識的能力,是對某種軟件知識/技能的有深度的精通,一種摸到它的根的深度,而不是已掌握的技能的種類和數量。這時無論誰用他掌握了多少種你不會的技能來嚇唬你都沒用,你對他的層次只有蔑視。通過幾年的學習和工作,要記住最重要的一點,永遠最重要:對自己學習IT知識能力的自信,一個程序員一生都要不停地進行高強度的學習,用心問問自己,有沒有這個自信?別用虛榮心來騙自己哦,如果沒有的話,那就不必花費你寶貴的時間向下看了,作者在此感謝你有耐心看到這里,現在建議你關閉這篇文章,趁著年輕,當機立斷轉行吧!

三、注重邏輯:成為一名職業程序員

好,再前進一點點,你就要成為一名職業程序員了,讓我們繼續來完成這個任務吧!我們在前一節提到過,“你發現一些個別的demo是極品,它所展現的程序邏輯結構是你設計不出來的,你現在有點更關心它的程序設計構架,甚于對你原始目的(某種相關的技術/技巧)的關注”,其實你是在關注這個demo程序作者的思維邏輯,所有程序的本質就是邏輯。技術你已經較好地掌握了,但只有完成邏輯能力的提高,你才能成為一名職業程序員。打一個比方吧,你會十八般武藝,刀槍棍棒都很精通,但就是力氣不夠,所以永遠都上不了戰場,這個力氣對程序員而言就是邏輯能力(其本質是一個人的數學修養,注意,不是數學知識)。邏輯能力也是逐步提高的,開始時你一定是用直觀的邏輯能力來編程的,怎么想就怎么編,不對就再改,在改進中提高自己的邏輯能力,從直觀邏輯能力提高到抽象邏輯能力,這是很正常的。提前說一句吧,到達邏輯能力的至高境界,其表現是用數學語言來描述問題和問題的解決辦法,高度抽象!好,說回來吧,你要提高邏輯能力,最快的辦法就是讀別人寫的結構優秀的程序。優秀的代碼是百讀不厭的(這句話是我抄來的),暫時放放對其中某種技術和技巧的關注吧,你要推導和學習的是這些好程序的邏輯結構,它們是被精心設計出來的。你可以先捂住這個demo程序,自己設計一個功能相同的程序結構,然后比較一下demo的程序結構,如果差距較大,那你就不應簡單地改進一下,而是要把demo作者設計的過程在心里復原一遍,做到這一點也許有點困難,但這種事干的多了,你就會越干越快,越來越得心應手,你的邏輯能力飛速提升,你能看得上的邏輯結構優秀的程序開始不多了,下一步就是練習。從工作中開始吧,如果你有空閑,你需要做至少兩類練習,一類是算法練習,所有的經典算法都是經典的邏輯,題目有的是,像個好學生一樣吧,每年的國內國際編程競賽都有邏輯要求非常高的題,你可以只選一兩道難題來做做。當你可以把復雜的單遞歸程序(只有A調A)變成非遞歸程序時,已經不錯了,如果你能看得懂雙遞歸程序(A調A、A調B、B調A、B調B都有),我為你鼓掌!你不必往下看了,我有點不好意思啦――班門弄斧,你快滾蛋吧!另一類是把以前和當前你工作中你不滿意的程序推倒重新設計一遍,這非常重要,省時省力,因為你熟悉需求,技術上也沒問題,目的就是改進程序的邏輯結構,很劃算哦,唯一要克服的就是:你對推翻以前工作中那點小小成就的心理障礙,如果你真想優秀,說句粗話:這點心理障礙算個屁,一遍遍反復地推倒已有的成果只能使自己快速進步,放手干吧,沒什么好可惜的,馬恩早就在《共.產.黨宣言》里說過了:在這個過程中,你失去的只有鎖鏈(禁錮你思想的鎖鏈)。

讓我們來總結一下,經過自我否定后,再生的你盡管對過去的“業績”還有一些眷戀,但已是一個初步具備職業水準的程序員了,掌握了相應的技術和技巧,具備了較高的抽象邏輯思維能力,最主要的特征是:能自覺地自我否定,不斷地追求更高水平的邏輯能力。

在這個過程中,如果你能注意以下一些小的方面,你前進的步伐也許會快一些。

l 從編譯原理的角度來理解你工作中使用的高級語言,如果你做到這一點,至少有兩個好處,第一個好處是避免一大堆低水平重復出現的編譯錯誤。一名優秀的Coder平均在一個工作日中應該完成200行以上的源碼,其編譯錯誤應該控制在5個以下,要知道這200行源碼不是一次完成的,所以大多數情況下你都要追求一次編譯通過,而一名職業水準的程序員,應該進一步做到即使用purify這類的工具來檢查源碼,也不會存在嚴重的內存泄露。第二個好處是可以提高源碼的可讀性和效率。規范地編寫你的代碼使你自己的邏輯清晰,因為你明白多加幾個括號和空行、多換行對齊、多注釋,編譯器是會自動識別的,不影響程序執行的效率,反過來,控制好遞歸調用和循環內的if語句才是提高程序效率的關鍵,要全力避免遞歸,但要深刻理解遞歸,能通過自己建立堆棧來把遞歸程序轉換成非遞歸程序,要求還是較高的哦!

l 避免思維陷阱,只要你是人就一定有自己的思維慣性,這一定又會表現在你的程序邏輯中,有時你就是從這個慣性中跳不出來(誰都有這個時候),但要心里有數才行,所以你需要幫助,如果你有幾個水平相若或更高的職業伙伴,太好了,當遇到花30分鐘還打不下的bug時,就別浪費時間了,找他們吧,最要緊的是能思路清晰明確地表述你的問題,通常你自己在這個過程中或者伙伴中就有人把問題解決了,又快又好。另外,有幾個可以良性競爭的職業伙伴是人生的一件幸事,1+1>2,大家各有所長,你最好做到及時公開你的成果,技不壓身嘛,IT發展的這么快,你再優秀,那點東東也沒有什么值得隱藏的,所以你可以技術或水平不夠高,但千萬不可以讓真正具有職業水準的選手鄙視你的職業品質和行為。

l 有自己debug的特點,下面的說法作者不敢太肯定,只是經驗之談。即使在VC這種高度完善的開放環境下,你仍然應該要求自己僅憑打印語句就能debug。這也有兩點好處,第一個好處是,遇到bug你會認真想問題所在,而不是用debug工具一步步簡單地追蹤卡在哪兒了,你定位bug范圍的方式是從大到小、從粗到精,這是一種自頂向下的思維方式,而用工具追蹤,容易形成自底向上的思維方式,這不算好,你應該先看到森林,再看到樹木。我反復提及:程序就是邏輯過程,大多數程序從main函數開始,是由數據結構和功能子程序組成的一個樹形結構的邏輯過程(要認清即使是面向對象的程序語言也是一樣的),它的執行過程是深度優先的,但你定位bug應該是廣度優先的,好好想想這一點,嗯?第二個好處是強迫你思考并記住而不是用工具看到調用過程,你大腦的抽象邏輯思維能力和胳膊上肌肉的力量一樣,都是練出來的,如果你的bug是程序結構上的邏輯錯誤引起的,這一點就非常重要了,順便說一句,最難打的bug就是程序邏輯結構錯誤導致的bug。你要是真正明明白白地認識到這兒了,那我就沒什么東西可以告訴你了。總之,程序員的職業水準:生產效率和程序質量,主要是取決于源碼中bug的數量和debug的速度,而不是取決于編寫源碼的速度。給你一個我自己定義的考查一個職業程序員的指標:一個合格水準的職業程序員,編程的時間如果算一份的話,其累計debug的時間不能超過一份,真正職業高手累計debug的時間應該控制在0.5份以下,如何?你關上門悄悄問問自己,你花費在編程和debug上的時間比例是多少?如果你把程序員作為自己一生的職業,那么就永遠都要牢記一點:追求做一個0 bug的優秀程序員!這是任何一個想成為職業程序員的人的理想,請相信:堅忍不拔地追求實現這個理想將讓你出類拔萃!

l 做好程序的單元測試,這是另一項考查你是否是一名具有合格職業水準的程序員的一個必要指標。其實在你拿到需求的時候就要準備單元測試用例了,并且這些用例將直接影響你的詳細設計(有關軟件設計本來是該放在第四節講的)。我們還是打比方吧,當你拿到一個需求時,除了分析它靜態的功能外,還應明確它動態的操作/執行過程,把這個動態過程明確地用流程圖畫出來,比如分為A~Z的26步,其中A又可以進一步分解為A1~A5的5步,直到不能再分解為止。又比如說A3步不可分解了,那么你應該把A3步的正常操作和所有五花八門的異常操作都列出來,確保正常的操作肯定正確,異常的操作起碼程序不退出才行。這樣你就要寫好多好多的測試用例,說句老實話,我也從來不寫!但我一般會列一個提綱,比如A3步有正常的操作a、b、c、d、e共5項,異常的操作有f、g、h、i、j、k、l、m、n共9項,你在進行單元測試時都應該跑一遍,這樣的程序都還不敢說質量如何好,但起碼可以說較穩定吧!如果要想在進行單元測試時干得快、效率高,那么在進行詳細設計時,你就應該把A3步中對所有正常操作和異常操作的判斷都設計好,在編程實現A3步時,使得程序的結構合理高效,對不對?所以,如果你在工作中是割裂地看待軟件工程中從需求、分析、設計、編程、測試等各個環節,恐怕水平很有限喔!但如果你在分析需求時就能看到測試的問題,并改進設計和實現,為此做好相應的準備工作,嘿嘿,整個軟件開發過程你的效率會高很多,通常你在一個開發團隊中就會高度自信的,你已越過當一名偏頗、露骨的高手的境界,成為一個平靜的高手,這可是The best in the best!,用周星星的話說:是高手之高高手,因為別人看不出你高在哪兒,沒見你有什么高招或特拚命干,但反正你就是干得又快又好、又省力。關于進行單元測試還有很多復雜的方法,在此本文只提到了最基本的一點,目的是讓你在工作上考慮周全、安排有序,其它的自己琢磨吧,沒有人能替你吃飽飯!

l 如果你是用C++編程,我再簡單談談有關內層釋放的一個小技巧,就是對所有你編寫的類,在構造和析構函數中加打印語句,統計每個類在運行程序時構造和析構的地方,如果是配對的,那么起碼沒有對象類一級的內層在程序運行結束時沒有釋放,然后你就可以把打印語句刪掉了,招數雖土,但管用!

l 還有其它一些好習慣,在這里我隨筆寫一些,你要是有不同看法也請一笑過之吧。編程時應該對齊縮進,一個縮進用一個tab鍵,一般是4個空格,嚴格遵守開發團隊的編程規范也是非常重要的。一個子程序不應超過30行(不算空行),其內多重循環不應超過3層,否則都應該分裂成兩個子程序,個別算法程序可以長一些,但也不宜超過200行。通常一個類的所有成員函數總和不宜超過1500行,多了就應該考慮分解成兩個類(這個工作最好在設計時就完成)。每完成一小段程序,比如15~30行,就立即編譯運行,不要假裝高手,先敲它一大堆程序,再編譯運行,妄想一次成功,體驗一種假爽的、虛榮的快感,或炫耀給別人看,這么做只能證明自己是一個不折不扣的傻瓜,裝酷而已。因為只要有一次不成功,你就會花費大量的時間來調程序,別人的進度在這時就遠遠地超過你了,平常心是道,還是修煉真功夫吧!孫子兵法里關于這一點有明確的闡述,我就不引用了,但建議你真的不要這么干,除非你確實就是這樣總是一次就成功的天才,那你還看這篇文章干什么呢?我又不是寫給你們這些天才們看的。再就是有學會買好書、讀好書,關于計算機和軟件方面的書太多了,時間有限,比如有一個叫侯捷的家伙,幾乎寫的每本書都不錯,張國峰的C++編程也不錯,這只是我的個人意見啊,好書多著呢,列出來比這篇文章長好多倍,我就不多說了。還有一招,要是你運氣好,能搞到一些著名軟件系統的源碼,好好讀讀吧,在此我只能告訴你,Linux操作系統的一些源碼不錯,是開放的,你可以合法地搞到,其它的不要說是我建議你侵犯知識版權啊!

四、天生神力:成為系統分析員

本來就論述如何成為一名職業程序員而言,本文已基本完成任務了,但《菜根譚》有言:竭世機樞,似一滴投于巨壑,窮諸玄辯,若一毫置于太虛。既已乘興到此,何妨多置一毫于太虛呢,作者不才,干脆盡興寫算了。

你要是運氣好,直接進入了一個嚴格規范生產的軟件企業就業,剛開始就應該是按別人做好的軟件設計來實現編程,你可以有機會直接學習軟件設計,當你積累的足夠多了,能夠對其中的一些設計提出好的改進建議,而且干得又快又好,就會漸漸地展露頭角,我相信你終有一天成為一名軟件設計人員(注意,不是軟件產品設計人員),步入系統分析員的行列,但這還需其它的一些條件和自我修煉。如果你在一個不規范的軟件企業工作,那也不錯,你很可能直接就有機會進行軟件設計,然后開發、測試,甚至還不得不自己定義需求,把軟件開發過程的各個環節走一個遍,當然這樣對你的要求更高,而且你也不容易得到及時有益的指點,在正態分布的情況下,你應該是成長的很慢。但不管就業的單位如何,如果你決心要成為頂尖軟件職業選手,通常什么客觀困難都阻擋不了你,然而你個人的因素可能會阻止你的前進。下面提出的觀點純屬一己之見,傷人自尊之處作者在此提前道歉,并建議你除非對本文有強烈的興趣,否則就請直接看第五節或放下別看了。丑話已說在前頭了,在各種軟件開發組織的發展過程中的事實也證明,只有少數程序員能成為系統分析員,我想這一點不是我杜撰的吧,因此你要是在看接下來的部分時感到氣憤難當,那也實在沒著,純屬活該,因為作者只是在說明自己的觀點而已,你最多可以呲之以鼻,表示一下你的輕蔑好了,但沒有任何理由可以罵人!

作者自己沒有到微軟面試過,但身處軟件行業,關于微軟的許多東東當然還是有耳聞的,據說微軟招聘一名程序員要過五個已經成為微軟程序員的面試關,而且是一票否決制,又據說大多數面試題并非編程,而是一些有關邏輯和智力的題,作者私下也做過許多流傳的微軟面試題,并對此做法深以為然。程序的本質就是邏輯,所以幾十年前就有人提出編程是一門藝術,而藝術是要靠天份的,這一點少有人反對。一個人的邏輯能力可以不斷提高,但其能到達的終極邏輯能力的層次必定為其天生智力所限制,這一點就讓人不易接受了。好笑啊!人們可以公開承認自己沒有某種或全部的藝術天份,但要說自己邏輯天份不夠,換句話說承認自己笨、IQ不夠高,往往是要怒發沖冠的,其實這又有什么區別呢?話都說到這兒了,再次建議你如果不夠自信,就跳過這一節吧,直接看第五節,好嗎?

好了,把話題說回來,你已經成為一門合格的職業程序員了,如果要想成為從事軟件系統設計的職業系統分析員,第一件事就是悄悄找一個標準智商測試的網站或其它渠道,嚴格認真的測一測自己的智商,如果IQ低于130(正常智商是110),就請別費勁了,打消掉成為系統分析員的念頭吧!好!好!先請你冷靜一下,好好想想,其實微軟面試時就是在測你的智商和邏輯數學素質呢,這就是本節的標題為“天生神力”的原因,因為設計就是從無到有地進行創造,無論是軟件還是其它行業都一樣,可以有借鑒的,沒有現成的,設計就是創造!如果你IQ在130以上,又決心要當一名職業軟件系統分析員,其實你不過是要準備好吃更大的苦而已,有什么好虛榮的呢?

修煉還是從基本功開始的,過程和成為一名職業程序員差不多。必須使用設計工具這一點是不用多說的。在工作中,你基本上遇到的是兩類方式的設計,一個是結構化設計,另一個是面向對象設計,就個人經驗而言,面向對象的設計更好。如果你工作中不得不采用結構化的設計,你必須熟練地掌握數據流圖和控制流圖的分析和設計,一般來講,如果你把一個軟件中用到的數據模型設計好了,針對功能化的流程,不難設計出數據流圖,但下一步設計控制流圖才是挑戰,如果你按照需求走不通設計好的控制流圖,那么你或別人在按照這個設計編程實現時,必定也走不通,沒有奇跡會發生,還是在設計階段嚴格要求吧,又有一點需要牢記:返工是最慢的。當你在進行控制流圖的設計時,也不要妄想得到需求人員提供給你明確的指點,通常他們要是能夠把需求的功能和操作次序寫完整的話,你應該就感恩戴德了,從需求中整理出功能、操作的拓撲次序和條件是你作為系統分析員的職責。看看,要是沒有一點圖論的基礎和拓撲學的入門知識,你是當不好一個職業系統分析員的,即使你天賦不錯,必要的數學和邏輯素質仍然不可或缺。也不用氣餒,永遠沒有最好的設計,只有更好的設計,反復地進行設計迭代,勇于推翻舊的設計,你將快速進步。如果你在工作中是采用面向對象進行設計的,那就更有利了,有關面向對象設計的書太多了,不用作者在此多費口舌,建議精讀一本經典的書,比如北大邵維忠等編譯的《面向對象的分析》,有些方法和技巧可能過時,但其邏輯的基本原理是非常正確的,其本質是,你在邏輯上是如何認識這個世界的,你就是如何設計軟件體系結構的,然后讀讀其它書,觸類旁通,自己創造機會多實踐,成功自然會到來的,總之,不管是結構化設計還是面向對象設計,評價一下自己的軟件系統設計方案吧,有好多指標呢,比如是否均勻和平衡?局部獨立性強不強?有沒有歧異的結構?有沒有層次太多或太少?有沒有某個層次太大、太廣?是不是邏輯結構先復雜了再化簡的?還是只會設計簡單的,復雜不起來(這一點是笨哦,如果出現多次,請你不要意氣用事,轉行吧)?最重要的一點,是否容易理解、實現和改進?你自己會得出評價的。如果有機會看到別人的設計,一定不要錯過學習的機會,自己推導一遍,認真比較比較,獲益會較多。

走到這一步,你就應該關注設計模式了,首先還是學習,這方面的好書有的是,但一般在工作中用到的設計模式較為單一,應該多嘗試一下其它的設計模式。其次必須要明白設計模式不是設計思路,也不能代替設計思路,比方你要從A到B修一條路,設計模式只是讓你選擇,是修水泥的還是柏油的?是高架路還是普通的,但線路必須你自己定,而線路就是設計思路,模式對思路是有影響,但不能代替,所以如果你的智商高達250,我相信你直接用匯編語言也能寫出面向對象的程序來。第三在此有一個陷阱,很多系統分析員生搬硬套設計模式,全然不懂如何融會貫通,在你的一項具體工作中,往往是以一種設計模式為主,其它模式為輔的,思維不拘泥于形式才是關鍵,而且也為你到達更高的軟件設計的境界做好準備。

唉!都不知該怎么向下寫好了,因為已達到作者水平的極限了,我胡亂說一點,你湊合看吧。軟件設計最終的層次是:以無法為有法、以無限為有限,這句話是李小龍說的,不是我說的。再拾人牙慧一把,類比一個故事吧,金大俠在《倚天屠龍記》里講到張無忌初學太極,學會的標志是把剛學的招數全忘了,記住的是太極的道理和精神,和李小龍有些相似喔,軟件設計也一樣,忘記所有的設計模式,隨心所欲進行設計才是至高境界,所以你能到達多高的軟件設計的境界最終將取決于你的哲學素質,這一點實在是不好寫啊,你自己領悟吧!作者只有祝福了!

五、職業人的終極目標:全面修煉,成為Leader

這一節更不好寫,涉及到太多其它非技術方面的因素,特別是個人人生觀和世界觀的修煉,如果本帖的點擊率超過作者私下期望的一個數值,那我就爭取盡力厚著臉皮再補上吧。我只說一句,雖然大家都知道軟件開發是一個團隊性的工作,但追求參與一個大型軟件系統的成功開發,是一名軟件人員的本能,就像拿破侖說的不想當元帥的士兵不是好士兵,所以不追求實現大系統的軟件人員,也不是一個好的職業軟件人員,但你只有成為Leader,領導一個優秀的軟件開發團隊,才有機會實現這個終極職業目標,對不對? 好吧,不管你現在的感受如何,我都謝謝你能讀到這里!我不習慣假謙虛,就不說什么作者水平有限,本文拋磚引玉,歡迎大家批評斧正之類的客套話了,雖然作者水平確實有限。所以我認為你盡管有權砸磚,但實在沒必要搞回帖、或回罵、或頂之類的玩意兒,我只是盡興寫一點多年從事軟件開發工作的體驗,因此接下來我就高掛免戰牌,不回復任何回帖了。再次謝謝你能有耐心讀到這里!希望本文對你有所裨益,祝你成功!再見!

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/carefree31441/archive/2008/07/10/2635287.aspx

第五篇:C語言嵌入式系統編程修煉之道

C語言嵌入式系統編程修煉之道收藏

C語言嵌入式系統編程修煉之道——背景篇...1 C語言嵌入式系統編程修煉之道——軟件架構篇...4 1.模塊劃分...4 2.多任務還是單任務...5 3.單任務程序典型架構...6 4.中斷服務程序...7 5.硬件驅動模塊...9 6.C的面向對象化...10 總結...10 C語言嵌入式系統編程修煉之道——內存操作篇...12 1.數據指針...12 2.函數指針...13 3.數組vs.動態申請...14 4.關鍵字const 15 5.關鍵字volatile.16 6.CPU字長與存儲器位寬不一致處理...17 總結...18 C語言嵌入式系統編程修煉之道——屏幕操作篇...19 1.漢字處理...19 2.系統時間顯示...20 3.動畫顯示...21 4.菜單操作...22 5.模擬MessageBox函數...24 總結...26 C語言嵌入式系統編程修煉之道——鍵盤操作篇...27 1.處理功能鍵...27 2.處理數字鍵...28 3.整理用戶輸入...29 總結...30 C語言嵌入式系統編程修煉之道——性能優化篇...31 1.使用宏定義...31 2.使用寄存器變量...31 3.內嵌匯編...32 4.利用硬件特性...32 5.活用位操作...33 總結

C語言嵌入式系統編程修煉之道——背景篇 不同于一般形式的軟件編程,嵌入式系統編程建立在特定的硬件平臺上,勢必要求其編程語言具備較強的硬件直接操作能力。無疑,匯編語言具備這樣的特質。但是,歸因于匯編語言開發過程的復雜性,它并不是嵌入式系統開發的一般選擇。而與之相比,C語言——一種“高級的低級”語言,則成為嵌入式系統開發的最佳選擇。筆者在嵌入式系統項目的開發過程中,一次又一次感受到C語言的精妙,沉醉于C語言給嵌入式開發帶來的便利。本文的目的在于進行“C語言嵌入式系統開發的內功心法”秀,一共包括25招。

圖1給出了本文的討論所基于的硬件平臺,實際上,這也是大多數嵌入式系統的硬件平臺。它包括兩部分:

(1)

以通用處理器為中心的協議處理模塊,用于網絡控制協議的處理;(2)

以數字信號處理器(DSP)為中心的信號處理模塊,用于調制、解調和數/模信號轉換。

本文的討論主要圍繞以通用處理器為中心的協議處理模塊進行,因為它更多地牽涉到具體的C語言編程技巧。而DSP編程則重點關注具體的數字信號處理算法,主要涉及通信領域的知識,不是本文的討論重點。

著眼于討論普遍的嵌入式系統C編程技巧,系統的協議處理模塊沒有選擇特別的CPU,而是選擇了眾所周知的CPU芯片——80186,每一位學習過《微機原理》的讀者都應該對此芯片有一個基本的認識,且對其指令集比較熟悉。80186的字長是16位,可以尋址到的內存空間為1MB,只有實地址模式。C語言編譯生成的指針為32位(雙字),高16位為段地址,低16位為段內編譯,一段最多64KB。

圖1 系統硬件架構

協議處理模塊中的FLASH和RAM幾乎是每個嵌入式系統的必備設備,前者用于存儲程序,后者則是程序運行時指令及數據的存放位置。系統所選擇的FLASH和RAM的位寬都為16位,與CPU一致。

實時鐘芯片可以為系統定時,給出當前的年、月、日及具體時間(小時、分、秒及毫秒),可以設定其經過一段時間即向CPU提出中斷或設定報警時間到來時向CPU提出中斷(類似鬧鐘功能)。

NVRAM(非易失去性RAM)具有掉電不丟失數據的特性,可以用于保存系統的設置信息,譬如網絡協議參數等。在系統掉電或重新啟動后,仍然可以讀取先前的設置信息。其位寬為8位,比CPU字長小。文章特意選擇一個與CPU字長不一致的存儲芯片,為后文中一節的討論創造條件。

UART則完成CPU并行數據傳輸與RS-232串行數據傳輸的轉換,它可以在接收到[1~MAX_BUFFER]字節后向CPU提出中斷,MAX_BUFFER為UART芯片存儲接收到字節的最大緩沖區。

鍵盤控制器和顯示控制器則完成系統人機界面的控制。以上提供的是一個較完備的嵌入式系統硬件架構,實際的系統可能包含更少的外設。之所以選擇一個完備的系統,是為了后文更全面的討論嵌入式系統C語言編程技巧的方方面面,所有設備都會成為后文的分析目標。

嵌入式系統需要良好的軟件開發環境的支持,由于嵌入式系統的目標機資源受限,不可能在其上建立龐大、復雜的開發環境,因而其開發環境和目標運行環境相互分離。因此,嵌入式應用軟件的開發方式一般是,在宿主機(Host)上建立開發環境,進行應用程序編碼和交叉編譯,然后宿主機同目標機(Target)建立連接,將應用程序下載到目標機上進行交叉調試,經過調試和優化,最后將應用程序固化到目標機中實際運行。

CAD-UL是適用于x86處理器的嵌入式應用軟件開發環境,它運行在Windows操作系統之上,可生成x86處理器的目標代碼并通過PC機的COM口(RS-232串口)或以太網口下載到目標機上運行,如圖2。其駐留于目標機FLASH存儲器中的monitor程序可以監控宿主機Windows調試平臺上的用戶調試指令,獲取CPU寄存器的值及目標機存儲空間、I/O空間的內容。圖2 交叉開發環境

后續章節將從軟件架構、內存操作、屏幕操作、鍵盤操作、性能優化等多方面闡述C語言嵌入式系統的編程技巧。軟件架構是一個宏觀概念,與具體硬件的聯系不大;內存操作主要涉及系統中的FLASH、RAM和NVRAM芯片;屏幕操作則涉及顯示控制器和實時鐘;鍵盤操作主要涉及鍵盤控制器;性能優化則給出一些具體的減小程序時間、空間消耗的技巧。

本文即將講述的25個主題可分為兩類,一類是編程技巧,有很強的適用性;一類則介紹嵌入式系統編程的一般常識,具有一定的理論意義。So, let’s go.C語言嵌入式系統編程修煉之道——軟件架構篇 1.模塊劃分

模塊劃分的“劃”是規劃的意思,意指怎樣合理的將一個很大的軟件劃分為一系列功能獨立的部分合作完成系統的需求。C語言作為一種結構化的程序設計語言,在模塊的劃分上主要依據功能(依功能進行劃分在面向對象設計中成為一個錯誤,牛頓定律遇到了相對論),C語言模塊化程序設計需理解如下概念:(1)

模塊即是一個.c文件和一個.h文件的結合,頭文件(.h)中是對于該模塊接口的聲明;

(2)

某模塊提供給其它模塊調用的外部函數及數據需在.h中文件中冠以extern關鍵字聲明;

(3)

模塊內的函數和全局變量需在.c文件開頭冠以static關鍵字聲明;(4)

永遠不要在.h文件中定義變量!定義變量和聲明變量的區別在于定義會產生內存分配的操作,是匯編階段的概念;而聲明則只是告訴包含該聲明的模塊在連接階段從其它模塊尋找外部函數和變量。如: /*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文件 */ 以上程序的結果是在模塊1、2、3中都定義了整型變量a,a在不同的模塊中對應不同的地址單元,這個世界上從來不需要這樣的程序。正確的做法是: /*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的話,對應的是同一片內存單元。一個嵌入式系統通常包括兩類模塊:

(1)硬件驅動模塊,一種特定硬件對應一個模塊;

(2)軟件功能模塊,其模塊的劃分應滿足低偶合、高內聚的要求。2.多任務還是單任務

所謂“單任務系統”是指該系統不能支持多任務并發操作,宏觀串行地執行一個任務。而多任務系統則可以宏觀并行(微觀上可能串行)地“同時”執行多個任務。

多任務的并發執行通常依賴于一個多任務操作系統(OS),多任務OS的核心是系統調度器,它使用任務控制塊(TCB)來管理任務調度功能。TCB包括任務的當前狀態、優先級、要等待的事件或資源、任務程序碼的起始地址、初始堆棧指針等信息。調度器在任務被激活時,要用到這些信息。此外,TCB還被用來存放任務的“上下文”(context)。任務的上下文就是當一個執行中的任務被停止時,所要保存的所有信息。通常,上下文就是計算機當前的狀態,也即各個寄存器的內容。當發生任務切換時,當前運行的任務的上下文被存入TCB,并將要被執行的任務的上下文從它的TCB中取出,放入各個寄存器中。嵌入式多任務OS的典型例子有Vxworks、ucLinux等。嵌入式OS并非遙不可及的神壇之物,我們可以用不到1000行代碼實現一個針對80186處理器的功能最簡單的OS內核,作者正準備進行此項工作,希望能將心得貢獻給大家。

究竟選擇多任務還是單任務方式,依賴于軟件的體系是否龐大。例如,絕大多數手機程序都是多任務的,但也有一些小靈通的協議棧是單任務的,沒有操作系統,它們的主程序輪流調用各個軟件模塊的處理程序,模擬多任務環境。3.單任務程序典型架構

(1)從CPU復位時的指定地址開始執行;(2)跳轉至匯編代碼startup處執行;

(3)跳轉至用戶主程序main執行,在main中完成: a.初試化各硬件設備;

b.初始化各軟件模塊; c.進入死循環(無限循環),調用各模塊的處理函數

用戶主程序和各模塊的處理函數都以C語言完成。用戶主程序最后都進入了一個死循環,其首選方案是: while(1){ } 有的程序員這樣寫: for(;;){ } 這個語法沒有確切表達代碼的含義,我們從for(;;)看不出什么,只有弄明白for(;;)在C語言中意味著無條件循環才明白其意。下面是幾個“著名”的死循環:(1)操作系統是死循環;(2)WIN32程序是死循環;(3)嵌入式系統軟件是死循環;

(4)多線程程序的線程處理函數是死循環。你可能會辯駁,大聲說:“凡事都不是絕對的,2、3、4都可以不是死循環”。Yes,you are right,但是你得不到鮮花和掌聲。實際上,這是一個沒有太大意義的牛角尖,因為這個世界從來不需要一個處理完幾個消息就喊著要OS殺死它的WIN32程序,不需要一個剛開始RUN就自行了斷的嵌入式系統,不需要莫名其妙啟動一個做一點事就干掉自己的線程。有時候,過于嚴謹制造的不是便利而是麻煩。君不見,五層的TCP/IP協議棧超越嚴謹的ISO/OSI七層協議棧大行其道成為事實上的標準? 經常有網友討論:

printf(“%d,%d”,++i,i++);

/* 輸出是什么?*/ c = a+++b;

/* c=? */ 等類似問題。面對這些問題,我們只能發出由衷的感慨:世界上還有很多有意義的事情等著我們去消化攝入的食物。實際上,嵌入式系統要運行到世界末日。4.中斷服務程序

中斷是嵌入式系統中重要的組成部分,但是在標準C中不包含中斷。許多編譯開發商在標準C上增加了對中斷的支持,提供新的關鍵字用于標示中斷服務程序(ISR),類似于__interrupt、#program interrupt等。當一個函數被定義為ISR的時候,編譯器會自動為該函數增加中斷服務程序所需要的中斷現場入棧和出棧代碼。

中斷服務程序需要滿足如下要求:(1)不能返回值;

(2)不能向ISR傳遞參數;

(3)ISR應該盡可能的短小精悍;

(4)printf(char * lpFormatString,?)函數會帶來重入和性能問題,不能在ISR中采用。

在某項目的開發中,我們設計了一個隊列,在中斷服務程序中,只是將中斷類型添加入該隊列中,在主程序的死循環中不斷掃描中斷隊列是否有中斷,有則取出隊列中的第一個中斷類型,進行相應處理。/* 存放中斷的隊列 */ typedef struct tagIntQueue { int intType;

/* 中斷類型 */ struct tagIntQueue *next;}IntQueue;

IntQueue lpIntQueueHead;

__interrupt ISRexample(){

int intType;

intType = GetSystemType();QueueAddTail(lpIntQueueHead, intType);/* 在隊列尾加入新的中斷 */ } 在主程序循環中判斷是否有中斷: While(1){ If(!IsIntQueueEmpty())

{

intType = GetFirstInt();

switch(intType)

/* 是不是很象WIN32程序的消息解析函數? */

{

/* 對,我們的中斷類型解析很類似于消息驅動 */

case xxx:

/* 我們稱其為“中斷驅動”吧? */

break;

case xxx:

break;

} }

} 按上述方法設計的中斷服務程序很小,實際的工作都交由主程序執行了。5.硬件驅動模塊

一個硬件驅動模塊通常應包括如下函數:(1)中斷服務程序ISR(2)硬件初始化

a.修改寄存器,設置硬件參數(如UART應設置其波特率,AD/DA設備應設置其采樣速率等);

b.將中斷服務程序入口地址寫入中斷向量表: /* 設置中斷向量表 */

m_myPtr = make_far_pointer(0l);/* 返回void far型指針void far * */

m_myPtr += ITYPE_UART;/* ITYPE_UART: uart中斷服務程序 */ /* 相對于中斷向量表首地址的偏移 */

*m_myPtr = &UART _Isr;

/* UART _Isr:UART的中斷服務程序 */(3)設置CPU針對該硬件的控制線

a.如果控制線可作PIO(可編程I/O)和控制信號用,則設置CPU內部對應寄存器使其作為控制信號;

b.設置CPU內部的針對該設備的中斷屏蔽位,設置中斷方式(電平觸發還是邊緣觸發)。

(4)提供一系列針對該設備的操作接口函數。例如,對于LCD,其驅動模塊應提供繪制像素、畫線、繪制矩陣、顯示字符點陣等函數;而對于實時鐘,其驅動模塊則需提供獲取時間、設置時間等函數。6.C的面向對象化

在面向對象的語言里面,出現了類的概念。類是對特定數據的特定操作的集合體。類包含了兩個范疇:數據和操作。而C語言中的struct僅僅是數據的集合,我們可以利用函數指針將struct模擬為一個包含數據和操作的“類”。下面的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);/* 行為:函數指針 */

int a;

/* 數據 */

int b;};我們可以利用C語言模擬出面向對象的三個特性:封裝、繼承和多態,但是更多的時候,我們只是需要將數據與行為封裝以解決軟件結構混亂的問題。C模擬面向對象思想的目的不在于模擬行為本身,而在于解決某些情況下使用C語言編程時程序整體框架結構分散、數據和函數脫節的問題。我們在后續章節會看到這樣的例子。總結

本篇介紹了嵌入式系統編程軟件架構方面的知識,主要包括模塊劃分、多任務還是單任務選取、單任務程序典型架構、中斷服務程序、硬件驅動模塊設計等,從宏觀上給出了一個嵌入式系統軟件所包含的主要元素。

請記住:軟件結構是軟件的靈魂!結構混亂的程序面目可憎,調試、測試、維護、升級都極度困難。

一個高尚的程序員應該是寫出如藝術作品般程序的程序員。

C語言嵌入式系統編程修煉之道——內存操作篇 1.數據指針

在嵌入式系統的編程中,常常要求在特定的內存單元讀寫內容,匯編有對應的MOV指令,而除C/C++以外的其它編程語言基本沒有直接訪問絕對地址的能力。在嵌入式系統的實際調試中,多借助C語言指針所具有的對絕對地址單元內容的讀寫能力。以指針直接操作內存多發生在如下幾種情況:

(1)

某I/O芯片被定位在CPU的存儲空間而非I/O空間,而且寄存器對應于某特定地址;

(2)

兩個CPU之間以雙端口RAM通信,CPU需要在雙端口RAM的特定單元(稱為mail box)書寫內容以在對方CPU產生中斷;

(3)

讀取在ROM或FLASH的特定單元所燒錄的漢字和英文字模。譬如:

unsigned char *p =(unsigned char *)0xF000FF00;*p=11;以上程序的意義為在絕對地址0xF0000+0xFF00(80186使用16位段地址和16位偏移地址)寫入11。在使用絕對地址指針時,要注意指針自增自減操作的結果取決于指針指向的數據類別。上例中p++后的結果是p= 0xF000FF01,若p指向int,即: int *p =(int *)0xF000FF00;p++(或++p)的結果等同于:p = p+sizeof(int),而p—(或—p)的結果是p = p-sizeof(int)。同理,若執行:

long int *p =(long int *)0xF000FF00;則p++(或++p)的結果等同于:p = p+sizeof(long int),而p—(或—p)的結果是p = p-sizeof(long int)。

記住:CPU以字節為單位編址,而C語言指針以指向的數據類型長度作自增和自減。理解這一點對于以指針直接操作內存是相當重要的。2.函數指針

首先要理解以下三個問題:

(1)C語言中函數名直接對應于函數生成的指令代碼在內存中的地址,因此函數名可以直接賦給指向函數的指針;

(2)調用函數實際上等同于“調轉指令+參數傳遞處理+回歸位置入棧”,本質上最核心的操作是將函數生成的目標代碼的首地址賦給CPU的PC寄存器;(3)因為函數調用的本質是跳轉到某一個地址單元的code去執行,所以可以“調用”一個根本就不存在的函數實體,暈?請往下看: 請拿出你可以獲得的任何一本大學《微型計算機原理》教材,書中講到,186 CPU啟動后跳轉至絕對地址0xFFFF0(對應C語言指針是0xF000FFF0,0xF000為段地址,0xFFF0為段內偏移)執行,請看下面的代碼:

typedef void(*lpFunction)();

/* 定義一個無參數、無返回類型的 */ /* 函數指針類型 */ lpFunction lpReset =(lpFunction)0xF000FFF0;

/* 定義一個函數指針,指向*/ /* CPU啟動后所執行第一條指令的位置 */ lpReset();

/* 調用函數 */ 在以上的程序中,我們根本沒有看到任何一個函數實體,但是我們卻執行了這樣的函數調用:lpReset(),它實際上起到了“軟重啟”的作用,跳轉到CPU啟動后第一條要執行的指令的位置。

記住:函數無它,唯指令集合耳;你可以調用一個沒有函數體的函數,本質上只是換一個地址開始執行指令!3.數組vs.動態申請

在嵌入式系統中動態內存申請存在比一般系統編程時更嚴格的要求,這是因為嵌入式系統的內存空間往往是十分有限的,不經意的內存泄露會很快導致系統的崩潰。

所以一定要保證你的malloc和free成對出現,如果你寫出這樣的一段程序: char * function(void){

char *p;

p =(char *)malloc(…);

if(p==NULL)?;

?

/* 一系列針對p的操作 */ return p;} 在某處調用function(),用完function中動態申請的內存后將其free,如下: char *q = function();? free(q);上述代碼明顯是不合理的,因為違反了malloc和free成對出現的原則,即“誰申請,就由誰釋放”原則。不滿足這個原則,會導致代碼的耦合度增大,因為用戶在調用function函數時需要知道其內部細節!

正確的做法是在調用處申請內存,并傳入function函數,如下: char *p=malloc(…);if(p==NULL)?;function(p);? free(p);p=NULL;而函數function則接收參數p,如下: void function(char *p){ ?

/* 一系列針對p的操作 */ } 基本上,動態申請內存方式可以用較大的數組替換。對于編程新手,筆者推薦你盡量采用數組!嵌入式系統可以以博大的胸襟接收瑕疵,而無法“海納”錯誤。畢竟,以最笨的方式苦練神功的郭靖勝過機智聰明卻范政治錯誤走反革命道路的楊康。

給出原則:

(1)盡可能的選用數組,數組不能越界訪問(真理越過一步就是謬誤,數組越過界限就光榮地成全了一個混亂的嵌入式系統);

(2)如果使用動態申請,則申請后一定要判斷是否申請成功了,并且malloc和free應成對出現!4.關鍵字const const意味著“只讀”。區別如下代碼的功能非常重要,也是老生長嘆,如果你還不知道它們的區別,而且已經在程序界摸爬滾打多年,那只能說這是一個悲哀: const int a;int const a;const int *a;int * const a;int const * a const;(1)關鍵字const的作用是為給讀你代碼的人傳達非常有用的信息。例如,在函數的形參前添加const關鍵字意味著這個參數在函數體內不會被修改,屬于“輸入參數”。在有多個形參的時候,函數的調用者可以憑借參數前是否有const關鍵字,清晰的辨別哪些是輸入參數,哪些是可能的輸出參數。

(2)合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的參數,防止其被無意的代碼修改,這樣可以減少bug的出現。const在C++語言中則包含了更豐富的含義,而在C語言中僅意味著:“只能讀的普通變量”,可以稱其為“不能改變的變量”(這個說法似乎很拗口,但卻最準確的表達了C語言中const的本質),在編譯階段需要的常數仍然只能以#define宏定義!故在C語言中如下程序是非法的: const int SIZE = 10;char a[SIZE];/* 非法:編譯階段不能用到變量 */ 5.關鍵字volatile C語言編譯器會對用戶書寫的代碼進行優化,譬如如下代碼: int a,b,c;a = inWord(0x100);/*讀取I/O空間0x100端口的內容存入a變量*/ b = a;a = inWord(0x100);/*再次讀取I/O空間0x100端口的內容存入a變量*/ c = a;很可能被編譯器優化為: int a,b,c;a = inWord(0x100);/*讀取I/O空間0x100端口的內容存入a變量*/ b = a;c = a;但是這樣的優化結果可能導致錯誤,如果I/O空間0x100端口的內容在執行第一次讀操作后被其它程序寫入新值,則其實第2次讀操作讀出的內容與第一次不同,b和c的值應該不同。在變量a的定義前加上volatile關鍵字可以防止編譯器的類似優化,正確的做法是: volatile int a;

volatile變量可能用于如下幾種情況:

(1)并行設備的硬件寄存器(如:狀態寄存器,例中的代碼屬于此類);(2)一個中斷服務子程序中會訪問到的非自動變量(也就是全局變量);(3)多線程應用中被幾個任務共享的變量。6.CPU字長與存儲器位寬不一致處理

在背景篇中提到,本文特意選擇了一個與CPU字長不一致的存儲芯片,就是為了進行本節的討論,解決CPU字長與存儲器位寬不一致的情況。80186的字長為16,而NVRAM的位寬為8,在這種情況下,我們需要為NVRAM提供讀寫字節、字的接口,如下: typedef unsigned char BYTE;typedef unsigned int WORD;

/* 函數功能:讀NVRAM中字節

* 參數:wOffset,讀取位置相對NVRAM基地址的偏移

* 返回:讀取到的字節值 */ extern BYTE ReadByteNVRAM(WORD wOffset){

LPBYTE lpAddr =(BYTE*)(NVRAM + wOffset * 2);/* 為什么偏移要×2? */

return *lpAddr;}

/* 函數功能:讀NVRAM中字

* 參數:wOffset,讀取位置相對NVRAM基地址的偏移

* 返回:讀取到的字 */ extern WORD ReadWordNVRAM(WORD wOffset){

WORD wTmp = 0;

LPBYTE lpAddr;

/* 讀取高位字節 */

lpAddr =(BYTE*)(NVRAM + wOffset * 2);

/* 為什么偏移要×2? */

wTmp +=(*lpAddr)*256;

/* 讀取低位字節 */

lpAddr =(BYTE*)(NVRAM +(wOffset +1)* 2);

/* 為什么偏移要×2? */

wTmp += *lpAddr;

return wTmp;}

/* 函數功能:向NVRAM中寫一個字節

*參數:wOffset,寫入位置相對NVRAM基地址的偏移 *

byData,欲寫入的字節 */ extern void WriteByteNVRAM(WORD wOffset, BYTE byData){

… }

/* 函數功能:向NVRAM中寫一個字 */ *參數:wOffset,寫入位置相對NVRAM基地址的偏移 *

wData,欲寫入的字 */ extern void WriteWordNVRAM(WORD wOffset, WORD wData){

… } 子貢問曰:Why偏移要乘以2? 子曰:請看圖1,16位80186與8位NVRAM之間互連只能以地址線A1對其A0,CPU本身的A0與NVRAM不連接。因此,NVRAM的地址只能是偶數地址,故每次以2為單位前進!

圖1 CPU與NVRAM地址線連接

子貢再問:So why 80186的地址線A0不與NVRAM的A0連接? 子曰:請看《IT論語》之《微機原理篇》,那里面講述了關于計算機組成的圣人之道。總結

本篇主要講述了嵌入式系統C編程中內存操作的相關技巧。掌握并深入理解關于數據指針、函數指針、動態申請內存、const及volatile關鍵字等的相關知識,是一個優秀的C語言程序設計師的基本要求。當我們已經牢固掌握了上述技巧后,我們就已經學會了C語言的99%,因為C語言最精華的內涵皆在內存操作中體現。

我們之所以在嵌入式系統中使用C語言進行程序設計,99%是因為其強大的內存操作能力!

如果你愛編程,請你愛C語言; 如果你愛C語言,請你愛指針; 如果你愛指針,請你愛指針的指針!

C語言嵌入式系統編程修煉之道——屏幕操作篇 1.漢字處理

現在要解決的問題是,嵌入式系統中經常要使用的并非是完整的漢字庫,往往只是需要提供數量有限的漢字供必要的顯示功能。例如,一個微波爐的LCD上沒有必要提供顯示“電子郵件”的功能;一個提供漢字顯示功能的空調的LCD上不需要顯示一條“短消息”,諸如此類。但是一部手機、小靈通則通常需要包括較完整的漢字庫。

如果包括的漢字庫較完整,那么,由內碼計算出漢字字模在庫中的偏移是十分簡單的:漢字庫是按照區位的順序排列的,前一個字節為該漢字的區號,后一個字節為該字的位號。每一個區記錄94個漢字,位號則為該字在該區中的位置。因此,漢字在漢字庫中的具體位置計算公式為:94*(區號-1)+位號-1。減1是因為數組是以0為開始而區號位號是以1為開始的。只需乘上一個漢字字模占用的字節數即可,即:(94*(區號-1)+位號-1)*一個漢字字模占用字節數,以16*16點陣字庫為例,計算公式則為:(94*(區號-1)+(位號-1))*32。漢字庫中從該位置起的32字節信息記錄了該字的字模信息。

對于包含較完整漢字庫的系統而言,我們可以以上述規則計算字模的位置。但是如果僅僅是提供少量漢字呢?譬如幾十至幾百個?最好的做法是: 定義宏:

# define EX_FONT_CHAR(value)

# define EX_FONT_UNICODE_VAL(value)(value), # define EX_FONT_ANSI_VAL(value)(value), 定義結構體:

typedef struct _wide_unicode_font16x16 { WORD value;

/* 內碼 */ BYTE data[32];/* 字模點陣 */ }Unicode;#define CHINESE_CHAR_NUM ?

/* 漢字數量 */ 字模的存儲用數組:

Unicode chinese[CHINESE_CHAR_NUM] = { {

EX_FONT_CHAR(“業”)

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}

} } 要顯示特定漢字的時候,只需要從數組中查找內碼與要求漢字內碼相同的即可獲得字模。如果前面的漢字在數組中以內碼大小順序排列,那么可以以二分查找法更高效的查找到漢字的字模。

這是一種很有效的組織小漢字庫的方法,它可以保證程序有很好的結構。2.系統時間顯示

從NVRAM中可以讀取系統的時間,系統一般借助NVRAM產生的秒中斷每秒讀取一次當前時間并在LCD上顯示。關于時間的顯示,有一個效率問題。因為時間有其特殊性,那就是60秒才有一次分鐘的變化,60分鐘才有一次小時變化,如果我們每次都將讀取的時間在屏幕上完全重新刷新一次,則浪費了大量的系統時間。

一個較好的辦法是我們在時間顯示函數中以靜態變量分別存儲小時、分鐘、秒,只有在其內容發生變化的時候才更新其顯示。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關鍵字強大威力的證明。當然,在C++語言里,static具有了更加強大的威力,它使得某些數據和函數脫離“對象”而成為“類”的一部分,正是它的這一特點,成就了軟件的無數優秀設計。3.動畫顯示

動畫是無所謂有,無所謂無的,靜止的畫面走的路多了,也就成了動畫。隨著時間的變更,在屏幕上顯示不同的靜止畫面,即是動畫之本質。所以,在一個嵌入式系統的LCD上欲顯示動畫,必須借助定時器。沒有硬件或軟件定時器的世界是無法想像的:

(1)

沒有定時器,一個操作系統將無法進行時間片的輪轉,于是無法進行多任務的調度,于是便不再成其為一個多任務操作系統;

(2)

沒有定時器,一個多媒體播放軟件將無法運作,因為它不知道何時應該切換到下一幀畫面;

(3)

沒有定時器,一個網絡協議將無法運轉,因為其無法獲知何時包傳輸超時并重傳之,無法在特定的時間完成特定的任務。

因此,沒有定時器將意味著沒有操作系統、沒有網絡、沒有多媒體,這將是怎樣的黑暗?所以,合理并靈活地使用各種定時器,是對一個軟件人的最基本需求!在80186為主芯片的嵌入式系統中,我們需要借助硬件定時器的中斷來作為軟件定時器,在中斷發生后變更畫面的顯示內容。在時間顯示“xx:xx”中讓冒號交替有無,每次秒中斷發生后,需調用ShowDot: void ShowDot(){ static BOOL bShowDot = TRUE;

/* 再一次領略static關鍵字的威力 */ if(bShowDot)

{ showChar(‘:’,xPos,yPos);} else

{ showChar(‘ ’,xPos,yPos);

} bShowDot =!bShowDot;} 4.菜單操作

無數人為之絞盡腦汁的問題終于出現了,在這一節里,我們將看到,在C語言中哪怕用到一丁點的面向對象思想,軟件結構將會有何等的改觀!筆者曾經是個笨蛋,被菜單搞暈了,給出這樣的一個系統: 圖1 菜單范例

要求以鍵盤上的“←→”鍵切換菜單焦點,當用戶在焦點處于某菜單時,若敲擊鍵盤上的OK、CANCEL鍵則調用該焦點菜單對應之處理函數。我曾經傻傻地這樣做著:

/* 按下OK鍵 */ void onOkKey(){ /* 判斷在什么焦點菜單上按下Ok鍵,調用相應處理函數 */ Switch(currentFocus){ case MENU1:

menu1OnOk();

break;case MENU2:

menu2OnOk();

break;? } } /* 按下Cancel鍵 */ void onCancelKey(){ /* 判斷在什么焦點菜單上按下Cancel鍵,調用相應處理函數 */ Switch(currentFocus){ case MENU1:

menu1OnCancel();

break;case MENU2:

menu2OnCancel();

break;? } } 終于有一天,我這樣做了:

/* 將菜單的屬性和操作“封裝”在一起 */ typedef struct tagSysMenu

{

char *text;

/* 菜單的文本 */

BYTE xPos;/* 菜單在LCD上的x坐標 */

BYTE yPos;/* 菜單在LCD上的y坐標 */

void(*onOkFun)();

/* 在該菜單上按下ok鍵的處理函數指針 */

void(*onCancelFun)();/* 在該菜單上按下cancel鍵的處理函數指針 */ }SysMenu, *LPSysMenu;當我定義菜單時,只需要這樣: 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();

} 程序被大大簡化了,也開始具有很好的可擴展性!我們僅僅利用了面向對象中的封裝思想,就讓程序結構清晰,其結果是幾乎可以在無需修改程序的情況下在系統中添加更多的菜單,而系統的按鍵處理函數保持不變。面向對象,真神了!5.模擬MessageBox函數

MessageBox函數,這個Windows編程中的超級猛料,不知道是多少入門者第一次用到的函數。還記得我們第一次在Windows中利用MessageBox輸出“Hello,World!”對話框時新奇的感覺嗎?無法統計,這個世界上究竟有多少程序員學習Windows編程是從MessageBox(“Hello,World!”,?)開始的。在我本科的學校,廣泛流傳著一個詞匯,叫做“‘Hello,World’級程序員”,意指入門級程序員,但似乎“‘Hello,World’級”這個說法更搞笑而形象。

圖2 經典的Hello,World!圖2給出了兩種永恒經典的Hello,World對話框,一種只具有“確定”,一種則包含“確定”、“取消”。是的,MessageBox的確有,而且也應該有兩類!這完全是由特定的應用需求決定的。

嵌入式系統中沒有給我們提供MessageBox,但是鑒于其功能強大,我們需要模擬之,一個模擬的MessageBox函數為:

/****************************************** /*

函數名稱:

MessageBox /*

功能說明:

彈出式對話框,顯示提醒用戶的信息 /*

參數說明:

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);/* 顯示字符串 */

/* 根據對話框類型決定是否顯示確定、取消 */

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是模式對話框,阻塞運行,等待按鍵 */

while((keyValue!= KEY_OK)||(keyValue!= KEY_CANCEL))

{ keyValue = getSysKey();} /* 返回按鍵類型 */ if(keyValue== KEY_OK){ return ID_OK;} else { return ID_CANCEL;} } 上述函數與我們平素在VC++等中使用的MessageBox是何等的神似啊?實現這個函數,你會看到它在嵌入式系統中的妙用是無窮的。總結

本篇是本系列文章中技巧性最深的一篇,它提供了嵌入式系統屏幕顯示方面一些很巧妙的處理方法,靈活使用它們,我們將不再被LCD上凌亂不堪的顯示內容所困擾。

屏幕乃嵌入式系統生存之重要輔助,面目可憎之顯示將另用戶逃之夭夭。屏幕編程若處理不好,將是軟件中最不系統、最混亂的部分,筆者曾深受其害。

C語言嵌入式系統編程修煉之道——鍵盤操作篇 1.處理功能鍵

功能鍵的問題在于,用戶界面并非固定的,用戶功能鍵的選擇將使屏幕畫面處于不同的顯示狀態下。例如,主畫面如圖1: 圖1 主畫面

當用戶在設置XX上按下Enter鍵之后,畫面就切換到了設置XX的界面,如圖2:

圖2 切換到設置XX畫面

程序如何判斷用戶處于哪一畫面,并在該畫面的程序狀態下調用對應的功能鍵處理函數,而且保證良好的結構,是一個值得思考的問題。

讓我們來看看WIN32編程中用到的“窗口”概念,當消息(message)被發送給不同窗口的時候,該窗口的消息處理函數(是一個callback函數)最終被調用,而在該窗口的消息處理函數中,又根據消息的類型調用了該窗口中的對應處理函數。通過這種方式,WIN32有效的組織了不同的窗口,并處理不同窗口情況下的消息。

我們從中學習到的就是:

(1)將不同的畫面類比為WIN32中不同的窗口,將窗口中的各種元素(菜單、按鈕等)包含在窗口之中;

(2)給各個畫面提供一個功能鍵“消息”處理函數,該函數接收按鍵信息為參數;

(3)在各畫面的功能鍵“消息”處理函數中,判斷按鍵類型和當前焦點元素,并調用對應元素的按鍵處理函數。

/* 將窗口元素、消息處理函數封裝在窗口中 */ struct windows {

BYTE currentFocus;

ELEMENT element[ELEMENT_NUM];

void(*messageFun)(BYTE keyValue);

… };/* 消息處理函數 */ void messageFunction(BYTE keyValue){

BYTE i = 0;

/* 獲得焦點元素 */

while((element [i].ID!= currentFocus)&&(i < ELEMENT_NUM))

{

i++;

}

/* “消息映射” */

if(i < ELEMENT_NUM)

{

switch(keyValue)

{

case OK:

element[i].OnOk();

break;

}

} } 在窗口的消息處理函數中調用相應元素按鍵函數的過程類似于“消息映射”,這是我們從WIN32編程中學習到的。編程到了一個境界,很多東西都是相通的了。其它地方的思想可以拿過來為我所用,是為編程中的“拿來主義”。

在這個例子中,如果我們還想玩得更大一點,我們可以借鑒MFC中處理MESSAGE_MAP的方法,我們也可以學習MFC定義幾個精妙的宏來實現“消息映射”。2.處理數字鍵

用戶輸入數字時是一位一位輸入的,每一位的輸入都對應著屏幕上的一個顯示位置(x坐標,y坐標)。此外,程序還需要記錄該位置輸入的值,所以有效組織用戶數字輸入的最佳方式是定義一個結構體,將坐標和數值捆綁在一起: /* 用戶數字輸入結構體 */ typedef struct tagInputNum

{

BYTE byNum;/* 接收用戶輸入賦值 */

BYTE xPos;

/* 數字輸入在屏幕上的顯示位置x坐標 */

BYTE yPos;

/* 數字輸入在屏幕上的顯示位置y坐標 */

}InputNum, *LPInputNum;那么接收用戶輸入就可以定義一個結構體數組,用數組中的各位組成一個完整的數字:

InputNum inputElement[NUM_LENGTH];/* 接收用戶數字輸入的數組 */ /* 數字按鍵處理函數 */ extern void onNumKey(BYTE num){

if(num==0|| num==1)/* 只接收二進制輸入 */

{ /* 在屏幕上顯示用戶輸入 */ DrawText(inputElement[currentElementInputPlace].xPos, inputElement[currentElementInputPlace].yPos, “%1d”, num);

/* 將輸入賦值給數組元素 */

inputElement[currentElementInputPlace].byNum = num;

/* 焦點及光標右移 */

moveToRight();

} } 將數字每一位輸入的坐標和輸入值捆綁后,在數字鍵處理函數中就可以較有結構的組織程序,使程序顯得很緊湊。3.整理用戶輸入

繼續第2節的例子,在第2節的onNumKey函數中,只是獲取了數字的每一位,因而我們需要將其轉化為有效數據,譬如要轉化為有效的XXX數據,其方法是:

/* 從2進制數據位轉化為有效數據:XXX */ void convertToXXX(){

BYTE i;

XXX = 0;

for(i = 0;i < NUM_LENGTH;i++)

{

XXX += inputElement[i].byNum*power(2, NUM_LENGTH1);

}

} 反之,我們也可能需要在屏幕上顯示那些有效的數據位,因為我們也需要能夠反向轉化:

/* 從有效數據轉化為2進制數據位:XXX */ void convertFromXXX(){

BYTE i;

XXX = 0;

for(i = 0;i < NUM_LENGTH;i++)

{

inputElement[i].byNum = XXX / power(2, NUM_LENGTH1)% 2;

}

} 當然在上面的例子中,因為數據是2進制的,用power函數不是很好的選擇,直接用“<< >>”移位操作效率更高,我們僅是為了說明問題的方便。試想,如果用戶輸入是十進制的,power函數或許是唯一的選擇了。總結

本篇給出了鍵盤操作所涉及的各個方面:功能鍵處理、數字鍵處理及用戶輸入整理,基本上提供了一個全套的按鍵處理方案。對于功能鍵處理方法,將LCD屏幕與Windows窗口進行類比,提出了較新穎地解決屏幕、鍵盤繁雜交互問題的方案。

計算機學的許多知識都具有相通性,因而,不斷追趕時髦技術而忽略基本功的做法是徒勞無意的。我們最多需要“精通”三種語言(精通,一個在如今的求職簡歷里泛濫成災的詞語),最佳拍檔是匯編、C、C++(或JAVA),很顯然,如果你“精通”了這三種語言,其它語言你應該是可以很快“熟悉”的,否則你就沒有“精通”它們。

C語言嵌入式系統編程修煉之道——性能優化篇 1.使用宏定義

在C語言中,宏是產生內嵌代碼的唯一方法。對于嵌入式系統而言,為了能達到性能要求,宏是一種很好的代替函數的方法。

寫一個“標準”宏MIN,這個宏輸入兩個參數并返回較小的一個:

錯誤做法:

#define MIN(A,B)(A <= B ? A : B)正確做法:

#define MIN(A,B)((A)<=(B)?(A):(B))對于宏,我們需要知道三點:(1)宏定義“像”函數;

(2)宏定義不是函數,因而需要括上所有“參數”;(3)宏定義可能產生副作用。下面的代碼:

least = MIN(*p++, b);將被替換為:

((*p++)<=(b)?(*p++):(b))發生的事情無法預料。

因而不要給宏定義傳入有副作用的“參數”。2.使用寄存器變量

當對一個變量頻繁被讀寫時,需要反復訪問內存,從而花費大量的存取時間。為此,C語言提供了一種變量,即寄存器變量。這種變量存放在CPU的寄存器中,使用時,不需要訪問內存,而直接從寄存器中讀寫,從而提高效率。寄存器變量的說明符是register。對于循環次數較多的循環控制變量及循環體內反復使用的變量均可定義為寄存器變量,而循環計數是應用寄存器變量的最好候選者。(1)

只有局部自動變量和形參才可以定義為寄存器變量。因為寄存器變量屬于動態存儲方式,凡需要采用靜態存儲方式的量都不能定義為寄存器變量,包括:模塊間全局變量、模塊內全局變量、局部static變量;

(2)

register是一個“建議”型關鍵字,意指程序建議該變量放在寄存器中,但最終該變量可能因為條件不滿足并未成為寄存器變量,而是被放在了存儲器中,但編譯器中并不報錯(在C++語言中有另一個“建議”型關鍵字:inline)。

下面是一個采用寄存器變量的例子: /* 求1+2+3+?.+n的值 */ WORD Addition(BYTE n){ register i,s=0;for(i=1;i<=n;i++){ s=s+i;} return s;} 本程序循環n次,i和s都被頻繁使用,因此可定義為寄存器變量。3.內嵌匯編

程序中對時間要求苛刻的部分可以用內嵌匯編來重寫,以帶來速度上的顯著提高。但是,開發和測試匯編代碼是一件辛苦的工作,它將花費更長的時間,因而要慎重選擇要用匯編的部分。

在程序中,存在一個80-20原則,即20%的程序消耗了80%的運行時間,因而我們要改進效率,最主要是考慮改進那20%的代碼。

嵌入式C程序中主要使用在線匯編,即在C程序中直接插入_asm{ }內嵌匯編語句:

/* 把兩個輸入參數的值相加,結果存放到另外一個全局變量中 */ int result;

void Add(long a, long *b)

{

_asm

{

MOV

AX, a

MOV

BX, b

ADD

AX, [BX]

MOV

result, AX

}

}

4.利用硬件特性

首先要明白CPU對各種存儲器的訪問速度,基本上是:

CPU內部RAM > 外部同步RAM > 外部異步RAM > FLASH/ROM 對于程序代碼,已經被燒錄在FLASH或ROM中,我們可以讓CPU直接從其中讀取代碼執行,但通常這不是一個好辦法,我們最好在系統啟動后將FLASH或ROM中的目標代碼拷貝入RAM中后再執行以提高取指令速度; 對于UART等設備,其內部有一定容量的接收BUFFER,我們應盡量在BUFFER被占滿后再向CPU提出中斷。例如計算機終端在向目標機通過RS-232傳遞數據時,不宜設置UART只接收到一個BYTE就向CPU提中斷,從而無謂浪費中斷處理時間;

如果對某設備能采取DMA方式讀取,就采用DMA讀取,DMA讀取方式在讀取目標中包含的存儲信息較大時效率較高,其數據傳輸的基本單位是塊,而所傳輸的數據是從設備直接送入內存的(或者相反)。DMA方式較之中斷驅動方式,減少了CPU 對外設的干預,進一步提高了CPU與外設的并行操作程度。5.活用位操作

使用C語言的位操作可以減少除法和取模的運算。在計算機程序中數據的位是可以操作的最小數據單位,理論上可以用“位運算”來完成所有的運算和操作,因而,靈活的位操作可以有效地提高程序運行的效率。舉例如下: /* 方法1 */ int i,j;i = 879 / 16;j = 562 % 32;

/* 方法2 */ int i,j;i = 879 >> 4;j = 562-(562 >> 5 << 5);對于以2的指數次方為“*”、“/”或“%”因子的數學運算,轉化為移位運算“<< >>”通常可以提高算法效率。因為乘除運算指令周期通常比移位運算大。

C語言位運算除了可以提高運算效率外,在嵌入式系統的編程中,它的另一個最典型的應用,而且十分廣泛地正在被使用著的是位間的與(&)、或(|)、非(~)操作,這跟嵌入式系統的編程特點有很大關系。我們通常要對硬件寄存器進行位設置,譬如,我們通過將AM186ER型80186處理器的中斷屏蔽控制寄存器的第低6位設置為0(開中斷2),最通用的做法是: #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);outword(INT_MASK, wTemp | INT_I2_MASK);判斷該位是否為1的做法是:

#define INT_I2_MASK

0x0040

wTemp = inword(INT_MASK);if(wTemp & INT_I2_MASK){

?

/* 該位為1 */ } 上述方法在嵌入式系統的編程中是非常常見的,我們需要牢固掌握。總結

在性能優化方面永遠注意80-20準備,不要優化程序中開銷不大的那80%,這是勞而無功的。

宏定義是C語言中實現類似函數功能而又不具函數調用和返回開銷的較好方法,但宏在本質上不是函數,因而要防止宏展開后出現不可預料的結果,對宏的定義和使用要慎而處之。很遺憾,標準C至今沒有包括C++中inline函數的功能,inline函數兼具無調用開銷和安全的優點。

使用寄存器變量、內嵌匯編和活用位操作也是提高程序效率的有效方法。除了編程上的技巧外,為提高系統的運行效率,我們通常也需要最大可能地利用各種硬件設備自身的特點來減小其運轉開銷,例如減小中斷次數、利用DMA傳輸方式等。

下載Java系統程序員修煉之道word格式文檔
下載Java系統程序員修煉之道.doc
將本文檔下載到自己電腦,方便修改和收藏,請勿使用迅雷等下載。
點此處下載文檔

文檔為doc格式


聲明:本文內容由互聯網用戶自發貢獻自行上傳,本網站不擁有所有權,未作人工編輯處理,也不承擔相關法律責任。如果您發現有涉嫌版權的內容,歡迎發送郵件至:645879355@qq.com 進行舉報,并提供相關證據,工作人員會在5個工作日內聯系你,一經查實,本站將立刻刪除涉嫌侵權內容。

相關范文推薦

    JAVA程序員面試題

    JAVA程序員面試題 第一,談談final, finally, finalize的區別。 final?修飾符(關鍵字)如果一個類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承。因此一個類不......

    java程序員(筆試)

    筆試 一. 選擇題 1. 從“員工”表的“姓名”字段中找出名字包含“瑪麗”的人,下面的哪條select語句正確 A. Select*from 員工 where姓名 =“__瑪麗__” B. Select*from 員工 w......

    java程序員面試題

    1、 你怎樣理解Struts,又那些配置文件,以及作用? 理解:http://ruixin.iteye.com/blog/899289 配置文件:struts.xml 作用:struts 框架mvc 實現低耦合,便于程序的維護~ 配置文件控制......

    java程序員招聘

    職位描述:1、參加基于 JAVA 技術的門戶網站的開發; 2、負責公司的網站開發維護及新產品的研發; 3、書寫技術文檔和制定開發規范; 4、從系統層面去合理析網站產品,并提供開發工程......

    java程序員之路

    JAVA程序員之路- - 每個人的學習方法是不同的,一個人的方法不見得適合另一個人,我只能是談自己的學習方法。因為我學習Java是完全自學的,從來沒有問過別人,所以學習的過程基本......

    JAVA程序員求職信

    JAVA程序員求職信范文 尊敬的領導: 您好!十分感謝您在百忙之中能翻閱我的自薦信。與公司是一種選擇,與我則是一種機會。在上千份大同小異的求職信中,我期望你手中的這份能給您......

    Java程序員簡歷

    個人簡歷 ********************************************************************* 基本信息 ********************************************************************* 姓......

    java程序員面試題

    姓名: 年齡: 工作年限: 1.int和Integer有什么區別?2.抽象類(abstract class)和接口(interface)有什么異同?3.List、Set、Map的區別?4.Spring支持的ORM有哪些,哪些是你用過的?5.使用Spri......

主站蜘蛛池模板: 国产女人好紧好爽| 东京热无码av男人的天堂| 欧美日韩亚洲精品瑜伽裤| 偷偷色噜狠狠狠狠的777米奇| 国产在线看片免费观看| 成人亚洲欧美日韩在线观看| 国产自偷亚洲精品页65页| 婷婷色香五月综合激激情| 美女极度色诱视频国产| 久久久久久亚洲精品成人| 亚洲欧洲无卡二区视頻| 日韩精品人妻系列无码专区| 韩国精品一区二区三区无码视频| 国产传媒麻豆剧精品av国产| 国产精品中文久久久久久久| 精品高潮呻吟99av无码视频| 99国产精品久久久久久久久久久| 久久久老熟女一区二区三区| 久久精品久久精品中文字幕| 久久综合少妇11p| 色一情一乱一伦一区二区三区| 99无码熟妇丰满人妻啪啪| 免费人妻无码不卡中文字幕18禁| 亚洲最大的熟女水蜜桃av网站| 亚洲成av人综合在线观看| 成人性爱视频在线观看| 亚洲高清最新av网站| 国产精品玖玖玖在线资源| 2021最新在线精品国自产拍视频| 麻豆精品国产精华精华液好用吗| 综合欧美日韩国产成人| 精品av一区二区三区不卡| 国产成人精品午夜福利软件| 特级欧美成人性a片| 欲色欲色天天天www| 久久国产劲爆∧v内射-百度| 40岁成熟女人牲交片| 亚洲日韩中文无码久久| 亚洲人午夜射精精品日韩| 好紧好湿好黄的视频| 午夜少妇性影院私人影院在线|