各路大牛的C語(yǔ)言編程建議和技巧,看完是不是有點(diǎn)頓悟?
(我還沒(méi)有看到過(guò)一篇講關(guān)于如何規(guī)劃整個(gè)事情的好文章,不過(guò)這部分可以是課程的一部分。要是能發(fā)現(xiàn)它們的特質(zhì),那很好;要是不認(rèn)同的話,那也很好;但如果能啟發(fā)你們思考為什么不認(rèn)同,那樣就更好了)。在任何情況下,都不應(yīng)該照搬我所說(shuō)的方式進(jìn)行編程;要用你認(rèn)為最好的編程方式來(lái)嘗試完成程序。請(qǐng)一以貫之而且毫不留情的這么做。
1、排版問(wèn)題
程序是一種出版物,這意味著程序員們會(huì)先閱讀(也許是幾天、幾周或幾年后的你自己閱讀),最后才輪到機(jī)器。機(jī)器的快樂(lè)就是程序能編譯,機(jī)器才不在乎程序?qū)懙挠卸嗝雌?,可是人們?yīng)該保持程序的美觀。有時(shí)人們會(huì)過(guò)度關(guān)心:用漂亮的打印機(jī)呆板地打印出漂亮的輸出,而這些輸出只是將所有介詞用英文文本以粗體字體凸顯出來(lái),都是些與程序無(wú)關(guān)的細(xì)節(jié)。雖然有很多人認(rèn)為程序就應(yīng)該像 Algol.68 所描述的一樣(有些系統(tǒng)甚至要求照搬該風(fēng)格編寫程序),可清晰的程序不會(huì)因?yàn)檫@樣的呈現(xiàn)而變得更清晰,只會(huì)使糟糕的程序變得更可笑。
對(duì)于清晰的程序來(lái)說(shuō),排版規(guī)范一向都是至關(guān)重要的。當(dāng)然,眾所周知最有用的是縮進(jìn),但是當(dāng)墨水遮蓋了意圖時(shí),就會(huì)控制住排版。因此即便堅(jiān)持使用簡(jiǎn)單的舊打字機(jī)輸出,也該意識(shí)到愚蠢的排版。避免過(guò)度修飾,比如保持注釋的簡(jiǎn)潔和靈活。通過(guò)程序整齊一致地說(shuō)出想表達(dá)的。接著往下看。
2、變量命名
對(duì)于變量名稱,長(zhǎng)度并不是名稱的價(jià)值所在,清晰的表達(dá)才是。不常用的全局變量可能會(huì)有一個(gè)很長(zhǎng)的名稱,像 maxphysaddr。在循環(huán)中每一行所使用的數(shù)組索引,并不需要取一個(gè)比 i 更詳盡的名字。取 index 或者 elementnumber 會(huì)輸入更多的字母(或調(diào)用文本編輯器),并且會(huì)遮蓋住計(jì)算的細(xì)節(jié)。當(dāng)變量名稱很長(zhǎng)時(shí),很難明白發(fā)生了什么。在一定程度上,這是排版問(wèn)題,看看下面
vs.
現(xiàn)實(shí)例子中的問(wèn)題會(huì)變得更糟。所以僅需把索引當(dāng)成符號(hào)來(lái)對(duì)待。
指針也需要合理的符號(hào)。np 僅僅只是作為指針 nodepointer 的助記符。如果一貫都遵從命名規(guī)范,那么很容易就能推斷出 np 表示“節(jié)點(diǎn)指針”。在下一篇文章中會(huì)提到更多。
同時(shí)在編程可讀性的其它方面,一致性也是極其重要的。假使變量名為 maxphysaddr,則不要給同級(jí)關(guān)系的變量取名 lowestaddress。
最后,我傾向于「最小長(zhǎng)度」但「最大信息量」的命名,并讓上下文補(bǔ)齊其余部分。例如:全局變量在使用時(shí)很少有上下文幫助理解,那么它們的命名相對(duì)而言更需要令人易懂。因此我稱 maxphyaddr 作為一個(gè)全局變量名,對(duì)于在本地定義和使用的指針來(lái)說(shuō) np 并不一定是 NodePoint。這是品味的問(wèn)題,但品味又與清晰度相關(guān)。
我避免在命名時(shí)嵌入大寫字母;它們的閱讀舒適性太別扭了,像糟糕的排版一樣令人心煩。
3、指針的使用
C語(yǔ)言不同尋常,因?yàn)樗试S指針指向任何事物。指針是鋒利的工具,像任何這樣的工具一樣,使用得當(dāng)可以產(chǎn)生令人愉悅的生產(chǎn)力,但使用不當(dāng)也可以造成極大的破壞。指針在學(xué)術(shù)界的名聲不太好,因?yàn)樗kU(xiǎn)了,莫名其妙地就變得糟糕的不行。但我認(rèn)為它是強(qiáng)大的符號(hào),它可以幫助我們清楚地自我表達(dá)。
思考:當(dāng)有指針指向?qū)ο髸r(shí),對(duì)于那個(gè)對(duì)象,確切地說(shuō)它只是名稱,其它什么也不是。聽(tīng)起來(lái)很瑣碎,但看看下面的兩個(gè)表達(dá)式:
第一個(gè)指向一個(gè) node(節(jié)點(diǎn)),第二個(gè)計(jì)算為(可以說(shuō))同一個(gè) node。但第二種形式是不太容易理解的表達(dá)式。這里解釋一下,因?yàn)槲覀儽仨氁?node 是什么,i 是什么,還要知道 i 和 node 與周圍程序之間相關(guān)的規(guī)則是什么。孤立的表達(dá)式并不能說(shuō)明 i 是 node 的有效索引,更不用提是我們想要元素的索引。
如果 i、j 和 k 都是 node 數(shù)組中的索引將很容易出差錯(cuò),而且連編譯器都不能幫助找出錯(cuò)誤。當(dāng)給子程序傳參數(shù)時(shí),尤其容易出錯(cuò):指針只是一個(gè)單獨(dú)的參數(shù);但在接收的子程序中必須認(rèn)為數(shù)組和索引是一體的。
計(jì)算為對(duì)象表達(dá)式本身,比該對(duì)象的地址更不易察覺(jué),而且容易出錯(cuò)。正確使用指針可以簡(jiǎn)化代碼:
vs.
如果想取下一個(gè)元素的 type 可以是
或
?i 前移,但其余的表達(dá)式必須保持不變;用指針的話,只需要做一件事,就是指針前移。
把排版因素也考慮進(jìn)來(lái)。對(duì)于處理連續(xù)的結(jié)構(gòu)體來(lái)說(shuō),使用指針比用表達(dá)式可讀性更好:只需要較少的筆墨,而且編譯器和計(jì)算機(jī)的性能消耗也很小。與此相關(guān)的問(wèn)題是,指針類型會(huì)影響指針正確使用,這也就允許在編譯階段使用一些有用的錯(cuò)誤檢測(cè),來(lái)檢查數(shù)組序列不能分開(kāi)。而且如果是結(jié)構(gòu)體,那么它們的標(biāo)簽字段就是其類型的提示。因此
是足以讓人明白的。如果是索引數(shù)組,數(shù)組將取一些精心挑選的名字,而且表達(dá)式也會(huì)變得更長(zhǎng):
此外,由于例子變得越來(lái)越大,額外的字符更加讓人惱火。
一般來(lái)說(shuō),如果發(fā)現(xiàn)代碼中包含許多相似并復(fù)雜的表達(dá)式,而且表達(dá)式計(jì)算為數(shù)據(jù)結(jié)構(gòu)中的元素,那么明智地使用指針可以消除這些問(wèn)題??紤]一下
看起來(lái)像利用復(fù)合表達(dá)式表示 p。有時(shí)這值得用一個(gè)臨時(shí)變量(這里的 p)或者把運(yùn)算提取成一個(gè)宏。
4、過(guò)程名稱
過(guò)程名稱應(yīng)該表明它們是做什么的,函數(shù)名稱應(yīng)該表明它們返回什么。函數(shù)通常在像 if 這樣的表達(dá)式使用,因此可讀性要好。
是沒(méi)有太大幫助的,因?yàn)椴荒芡茢喑?checksize 錯(cuò)誤時(shí)返回 true,還是非錯(cuò)誤時(shí)返回。相反
使這點(diǎn)能清晰表達(dá),并且在常規(guī)使用中將來(lái)也不大可能出錯(cuò)。
5、注釋
這一個(gè)微妙的問(wèn)題,需要自己體會(huì)和判斷。由于一些原因,我傾向于寧可清除注釋。第一,假如代碼清晰,并且使用了規(guī)范的類型名稱和變量名稱,應(yīng)該從代碼本身就可以理解。第二,編譯器不能檢查注釋,因此不能保證準(zhǔn)確,特別是代碼修改過(guò)以后。誤導(dǎo)性的注釋會(huì)非常令人困惑。第三,排版問(wèn)題:注釋會(huì)使代碼變得雜亂。
但有時(shí)我會(huì)寫注釋,像下文一樣僅僅只是把它們用于介紹。例如:解釋全局變量的使用和類型(我總是在龐大的程序中寫注釋);作為一個(gè)不尋?;蛘哧P(guān)鍵過(guò)程的介紹;或標(biāo)記出大規(guī)模計(jì)算的一節(jié)。
有一個(gè)糟糕注釋風(fēng)格的例子:
還有更糟糕的做法:
先不要嘲笑,等到在現(xiàn)實(shí)中看到再去吧!
或許除了諸如重要數(shù)據(jù)結(jié)構(gòu)的聲明(對(duì)數(shù)據(jù)的注釋通常比對(duì)算法的更有幫助),這樣至關(guān)重要部分之外,需要避免對(duì)注釋的“可愛(ài)”排版和大段的注釋;基本上最好就不要寫注釋。如果代碼需要靠注釋來(lái)說(shuō)明,那最好的方法是重寫代碼,以便能更容易地理解。這就把我們帶到了復(fù)雜度。
6、復(fù)雜度
許多程序過(guò)于復(fù)雜,比需要有效解決的問(wèn)題更加復(fù)雜。這是為什么呢?大部分是由于設(shè)計(jì)不好,但我會(huì)跳過(guò)這個(gè)問(wèn)題,因?yàn)檫@個(gè)問(wèn)題太大了。然而程序往往在微觀層面就很復(fù)雜,有關(guān)這些可以在這里解決。
- 規(guī)則 1:不要斷定程序會(huì)在什么地方耗費(fèi)運(yùn)行時(shí)間。 瓶頸總是出現(xiàn)在令人意想不到的地方,直到證實(shí)瓶頸在哪,不要試圖再次猜測(cè)并加快運(yùn)行速度。
- 規(guī)則 2:估量(measure) 在沒(méi)有對(duì)代碼做出估量之前不要優(yōu)化速度,除非發(fā)現(xiàn)最耗時(shí)的那部分代碼,要不也不要去做。
- 規(guī)則 3:當(dāng) n 很小時(shí)(通常也很?。ㄉ诘乃惴ㄟ\(yùn)行很慢。 花哨算法有很大的常數(shù)級(jí)別復(fù)雜度。在你確定 n 總是很大之前, 不要使用花哨算法。(即使假如 n 變大,也優(yōu)先使用規(guī)則 2).例如,對(duì)于常見(jiàn)問(wèn)題,二叉樹(shù)總比伸展樹(shù)高效。
- 規(guī)則 4:花哨的算法比簡(jiǎn)單的算法更容易有 bug,而且實(shí)現(xiàn)起來(lái)也更困難 盡量使用簡(jiǎn)單的算法與簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu)。
- 數(shù)組
- 鏈表
- 哈希表
- 二叉樹(shù)
當(dāng)然也必須要有把這些數(shù)據(jù)結(jié)構(gòu)靈活結(jié)合的準(zhǔn)備,比如用哈希表實(shí)現(xiàn)的符號(hào)表,其中哈希表是由字符型數(shù)組組成的鏈表。
- 規(guī)則 5:以數(shù)據(jù)為核心 如果選擇了適當(dāng)?shù)臄?shù)據(jù)結(jié)構(gòu)并把一切都組織得很有條理性,算法總是不言而喻的。編程的核心是數(shù)據(jù)結(jié)構(gòu),而不是算法。(參考 Brooks p. 102)
- 規(guī)則 6:就是沒(méi)有規(guī)則 6。
7、數(shù)據(jù)編程
不像許多 if 語(yǔ)句,算法或算法的細(xì)節(jié)通常以緊湊、高效和明確的數(shù)據(jù)進(jìn)行編碼。眼前的工作可以編碼,歸根到底是由于其復(fù)雜性都是由不相干的細(xì)節(jié)組合而成。分析表是典型例子,它通過(guò)一種解析固定、簡(jiǎn)單代碼段的形式,對(duì)編程語(yǔ)言的語(yǔ)法進(jìn)行編碼。有限狀態(tài)機(jī)特別適合這種處理形式,但是幾乎任何涉及到對(duì)構(gòu)建數(shù)據(jù)驅(qū)動(dòng)算法有益的程序,都是將某些抽象數(shù)據(jù)類型的輸入“解析”成序列,序列會(huì)由一些獨(dú)立“動(dòng)作”構(gòu)成。
也許這種設(shè)計(jì)最有趣的地方是表結(jié)構(gòu)有時(shí)可以由另一個(gè)程序生成(經(jīng)典案例是解析生成器)。有個(gè)更接地氣的例子,假如操作系統(tǒng)是由一組表驅(qū)動(dòng),這組表包含連接 I/O 請(qǐng)求到相應(yīng)設(shè)備驅(qū)動(dòng)的操作,那么可以通過(guò)程序“配置“系統(tǒng),該程序可以讀取到某些特殊設(shè)備與可疑機(jī)器連接的描述,并打印相應(yīng)的表。
數(shù)據(jù)驅(qū)動(dòng)程序在初學(xué)者中不常見(jiàn)的原因之一是由于 Pascal 的專制。 Pascal 像它的創(chuàng)始人一樣,堅(jiān)信代碼要和數(shù)據(jù)分開(kāi)。因而(至少在原始形式上)無(wú)法創(chuàng)建初始化的數(shù)據(jù)。與圖靈和馮諾依曼的理論背道而馳,這些理論可都是定義存儲(chǔ)計(jì)算機(jī)的基本原理。代碼和數(shù)據(jù)是一樣的,或至少可以算是。還能怎樣解釋編譯器的工作原理呢?(函數(shù)式語(yǔ)言對(duì) I/O 也有類似的問(wèn)題)
8、函數(shù)指針
Pascal 專制的另一個(gè)結(jié)果是初學(xué)者不使用函數(shù)指針。(在 Pascal 中沒(méi)有把函數(shù)作為變量) 用函數(shù)指針來(lái)處理編碼復(fù)雜度會(huì)有一些令人感興趣的地方。
指針指向的程序有一定的復(fù)雜度。這些程序必須遵守一些標(biāo)準(zhǔn)協(xié)議,像要求一組都是相同調(diào)用的程序就是其中之一。除此之外,所要實(shí)現(xiàn)的只是完成業(yè)務(wù),復(fù)雜度是分散的。
有個(gè)協(xié)議的主張是既然所有使用的功能相似,那么它們的行為也必須相似。這對(duì)簡(jiǎn)單的文檔、測(cè)試、程序擴(kuò)展和甚至使程序通過(guò)網(wǎng)絡(luò)分布都有幫助——遠(yuǎn)程過(guò)程調(diào)用可以通過(guò)該協(xié)議進(jìn)行編碼。
我認(rèn)為面相對(duì)象編程的核心是清晰使用函數(shù)指針。規(guī)定好要對(duì)數(shù)據(jù)執(zhí)行的一系列操作,以及對(duì)這些操作響應(yīng)的整套數(shù)據(jù)類型。將程序合攏到一起最簡(jiǎn)單的方法是為每種類型使用一組函數(shù)指針。簡(jiǎn)而言之,就是定義類和方法。當(dāng)然,面向?qū)ο笳Z(yǔ)言提供了更多更漂亮的語(yǔ)法、派生類型等等,但在概念上幾乎沒(méi)有提出額外的東西。
數(shù)據(jù)驅(qū)動(dòng)程序與函數(shù)指針的結(jié)合,變成了一種表現(xiàn)令人驚訝的工作方法。根據(jù)我的經(jīng)驗(yàn),這種方法經(jīng)常會(huì)產(chǎn)生驚喜的結(jié)果。即使沒(méi)有面向?qū)ο笳Z(yǔ)言,無(wú)需額外的工作也可以獲得 90% 的好處,并且能更好地管理結(jié)果。我無(wú)法再推薦出更高標(biāo)準(zhǔn)的實(shí)現(xiàn)方式。我所有的程序都是由這種方式組織管理,而且經(jīng)過(guò)多次開(kāi)發(fā)后都相安無(wú)事——遠(yuǎn)遠(yuǎn)優(yōu)于缺少約束的方法。也許正如所說(shuō):從長(zhǎng)遠(yuǎn)來(lái)看,約束會(huì)帶來(lái)豐厚的回報(bào)。
9、包含文件
簡(jiǎn)單規(guī)則:包含(include)文件時(shí)應(yīng)該永遠(yuǎn)不要嵌套包含。 如果聲明(在注釋或隱式聲明里)需要的文件沒(méi)有優(yōu)先包含進(jìn)來(lái),那么使用者(程序員)要決定包含哪些文件,但要以簡(jiǎn)單的方式處理,并采用避免多重包含的結(jié)構(gòu)。多重包含是系統(tǒng)編程的禍根。將文件包含五次或更多次來(lái)編譯一個(gè)單獨(dú)的 C 源文件的事情屢見(jiàn)不鮮。Unix 系統(tǒng)中 /usr/include/sys 就用了這么可怕的方式。
說(shuō)到 #ifdef,有一個(gè)小插曲,雖然它能防止讀取兩次文件,但實(shí)際上經(jīng)常用錯(cuò)。#ifdef 是定義在文件本身中,而不是文件包含它。結(jié)果是常常導(dǎo)致讓成千上萬(wàn)不必要的代碼通過(guò)詞匯分析器,這是(優(yōu)秀編譯器中)耗費(fèi)最大的階段。
只需遵從以上簡(jiǎn)單規(guī)則,就能讓你的代碼變得優(yōu)雅而美觀,至少也是賞心悅目,從技術(shù)變成藝術(shù)~~
10、延伸閱讀
有人認(rèn)為,現(xiàn)在是java和.net的時(shí)代,有誰(shuí)還需要C以及匯編呢?孰不知,java和.net是建立在軟件之上的,是為了壟斷市場(chǎng)而建立起來(lái)的體系, 猶如挖好一個(gè)金壁輝煌的坑,請(qǐng)你往下跳,還自以為站在巨人的肩膀上,事實(shí)上成了坑底之蛙。要成為一個(gè)真正的程序員,并期望成為一個(gè)程序員高手,必須從機(jī)器 出發(fā),從cpu到操作系統(tǒng),再到軟件體系,高手的境界就是悟道后的明鏡靈臺(tái),軟件設(shè)計(jì)出神入化,我就是程序,程序就是我。
旁觀者李四說(shuō):此人大笨也!我用鼠標(biāo)隨便拖幾個(gè)控件,就是一個(gè)xxx管理系統(tǒng)了,你用C語(yǔ)言怕是一年也寫不出來(lái)吧!好吧,我要承認(rèn),講這話的都已經(jīng)是mS 的奴才了,別的我不了解,MFC本身就是一個(gè)封閉的架構(gòu),從MFC入手學(xué)習(xí),你只會(huì)形成一種封閉的思維模式,因?yàn)镸S希望很多人只學(xué)會(huì)表面的東西,不致成 為高手,所以它大力推薦所謂的可視化的程序開(kāi)發(fā)工具,也真有很多人愿意上他的當(dāng),最后真正迷失方向。說(shuō)他坐不了程序吧,他也可以作,但是如果程序復(fù)雜一 點(diǎn),出現(xiàn)問(wèn)題時(shí),問(wèn)題出再哪里就搞不清楚了,反正是不清楚!
梁肇新,大牛啊,他說(shuō):"我就搞不懂了,用鼠標(biāo)怎么寫程序呢?在我的公司里,高手的鍵盤響個(gè)不停,鼠標(biāo)偶爾響一下,新手是鼠標(biāo)響個(gè)不停,鍵盤偶爾響一下,他們的薪水相差的就不是一倍那么多了!"
C語(yǔ)言是各大操作系統(tǒng)的基礎(chǔ),Unix、Linux、Windows其內(nèi)核都清一色是C語(yǔ)言開(kāi)發(fā)的,(某些地方是和匯編語(yǔ)言混合開(kāi)發(fā)的),君不見(jiàn) WindowsAPI都是C語(yǔ)言函數(shù)的接口?Unix/Linux絕大多數(shù)應(yīng)用都是C語(yǔ)言開(kāi)發(fā)的;Windows應(yīng)用程序用純API開(kāi)發(fā)已然不多,大多都是依靠某種ApplicationFramework,比如所謂的VC ,其實(shí)就是指VCIDE C 語(yǔ)言 MFC(現(xiàn)在重點(diǎn)已轉(zhuǎn)向ATL、 WTL),但是Windows服務(wù)、網(wǎng)絡(luò)、驅(qū)動(dòng)程序等底層軟件,還是C語(yǔ)言開(kāi)發(fā)的。各種語(yǔ)言的編譯器,包括java虛擬機(jī),都是用C語(yǔ)言開(kāi)發(fā)的。各種嵌入 式設(shè)備,如手機(jī)、PDA也都是C語(yǔ)言開(kāi)發(fā)的。
下面是一些個(gè)人建議:
1、多看課本、代碼
由于C語(yǔ)言靈活、強(qiáng)大,初學(xué)者要全面地掌握它非常吃力,因此在學(xué)習(xí)C語(yǔ)言的過(guò)程中,要多看課本、代碼,課本上沒(méi)有的可以上網(wǎng)搜索。
首先,一定要熟練掌握變量、常量、基本數(shù)據(jù)類型、庫(kù)函數(shù)及特點(diǎn)和運(yùn)用、運(yùn)算符、表達(dá)式及語(yǔ)句、C語(yǔ)言編寫的基本格式。
再次,要掌握C語(yǔ)言的流程控制語(yǔ)句、數(shù)組、函數(shù)、指針等基礎(chǔ)知識(shí),上述知識(shí)熟練后就可以學(xué)習(xí)鏈表、隊(duì)列、樹(shù)、圖等知識(shí)。最后要熟練各個(gè)知識(shí)點(diǎn)的運(yùn)用,可以把學(xué)習(xí)的重點(diǎn)放在函數(shù)的設(shè)計(jì)框架、參數(shù)設(shè)計(jì)、返回值設(shè)計(jì)等關(guān)鍵問(wèn)題上。
2、學(xué)好數(shù)學(xué)、英語(yǔ)
在C語(yǔ)言的學(xué)習(xí)過(guò)程中,一般有大量的算法和數(shù)據(jù)結(jié)構(gòu)需要去了解,許多算數(shù)運(yùn)算和邏輯運(yùn)算、關(guān)系運(yùn)算、循環(huán)結(jié)構(gòu)都可以利用數(shù)學(xué)知識(shí)來(lái)完成的,同樣許多算法都是為了完成數(shù)學(xué)領(lǐng)域的計(jì)算。編寫程序是為了讓計(jì)算機(jī)可以代替人操作運(yùn)算過(guò)程,從而減少人力??梢?jiàn),數(shù)學(xué)在計(jì)算機(jī)學(xué)習(xí)中的重要地位,有了數(shù)學(xué)知識(shí),你會(huì)發(fā)現(xiàn)數(shù)據(jù)結(jié)構(gòu)與算法原來(lái)也是很簡(jiǎn)單的。
同理,在C語(yǔ)言的學(xué)習(xí)過(guò)程中,我們會(huì)用到大量的英語(yǔ)知識(shí)。對(duì)于編程來(lái)說(shuō),英語(yǔ)的作用體現(xiàn)在閱讀英文文檔,適應(yīng)國(guó)際化的編程環(huán)境,我們要記住常用的一些C語(yǔ)言中用到的詞匯,也就是諸多的關(guān)鍵字。
3、理論聯(lián)系實(shí)踐,重視上機(jī)試驗(yàn)
計(jì)算機(jī)專業(yè)的大部分課程都是通過(guò)實(shí)踐來(lái)檢驗(yàn)學(xué)習(xí)成果的,更重要的是,要將所學(xué)的理論知識(shí)都要在實(shí)踐中更好的發(fā)揮。編程序是個(gè)實(shí)干的活,光說(shuō)不練不行。剛開(kāi)始學(xué)的時(shí)候,可以多練習(xí)書上的習(xí)題。對(duì)于自己不明白的地方,自己編個(gè)小程序?qū)嶒?yàn)一下是最好的方法,能給自己留下深刻的印象。自己動(dòng)手的過(guò)程中,要不斷糾正自己不好的編程習(xí)慣和認(rèn)識(shí)錯(cuò)誤。
C語(yǔ)言也是一門實(shí)踐性很強(qiáng)的課程,既要掌握概念,又要?jiǎng)邮志幊?、上機(jī)調(diào)試運(yùn)行。養(yǎng)成上機(jī)前分析題目,并編出程序源代碼的好習(xí)慣,編程時(shí)要注意程序的格式、標(biāo)點(diǎn)符號(hào)等,同時(shí)調(diào)試程序時(shí)要有耐心,有時(shí)一個(gè)程序可能要修改多次,甚至于費(fèi)了不少勁還是沒(méi)結(jié)果。要不斷向老師或者同學(xué)請(qǐng)教,不斷地查閱資料,所以編程千萬(wàn)不可遇難而退,這個(gè)時(shí)候是決定你水平提高的關(guān)鍵,一定要堅(jiān)持到底。大家對(duì)自己要有自信,對(duì)學(xué)好C語(yǔ)言課程要有信心,這樣我們才會(huì)有一個(gè)好的學(xué)習(xí)狀態(tài)并改正BUG。
程序調(diào)試成功后,要總結(jié)分析出自己在編寫程序時(shí)都出現(xiàn)了那些不足,在以后的解題過(guò)程中自己應(yīng)該注意的問(wèn)題。上機(jī)調(diào)式程序成功后要完成實(shí)驗(yàn)報(bào)告,逐步積累調(diào)試程序的經(jīng)驗(yàn)。培養(yǎng)自己良好的編程習(xí)慣。
4、養(yǎng)成良好的編程習(xí)慣
(1)在比較復(fù)雜的代碼后面要有注釋。如果光溜溜一堆代碼,別人就不可能看懂你的代碼,而且也不利于查找錯(cuò)誤。除非你一直編東西給自己看。能在代碼里說(shuō)明白的就一定要在代碼里體現(xiàn)。比如變量名、函數(shù)名,在命名的時(shí)候盡量說(shuō)明是干什么用的。
(2)注意語(yǔ)句的嵌套不要太長(zhǎng),把主函數(shù)盡量寫簡(jiǎn)短。經(jīng)常看到別人的代碼是主函數(shù)只有幾行,幾個(gè)函數(shù)調(diào)用,而定義全在主函數(shù)外部。這樣一是減少了主函數(shù)內(nèi)部的嵌套,二是比較精簡(jiǎn),容易讀懂。
(3)注意語(yǔ)句的選擇。并不是分支語(yǔ)句就用if循環(huán)就用while、for。在適當(dāng)?shù)那闆r下switch和dowhile語(yǔ)句也是要用的。在某些時(shí)候,switch語(yǔ)句比if語(yǔ)句更加精練明了,而dowhile比while少一個(gè)循環(huán)。
那么,如何學(xué)好單片機(jī)C語(yǔ)言?
很多想學(xué)單片機(jī)的人問(wèn)我的第一句話就是怎樣才能學(xué)好單片機(jī)?對(duì)于這個(gè)問(wèn)題我今天就我自己是如何開(kāi)始學(xué)單片機(jī),如何開(kāi)始上手,如何開(kāi)始熟練這個(gè)過(guò)程給大家講講。
先說(shuō)說(shuō)單片機(jī),一般我們現(xiàn)在用的比較多的的MCS-51的單片機(jī),它的資料比較多,用的人也很多,市場(chǎng)也很大。就我個(gè)人的體會(huì)怎么樣才能更快的學(xué)會(huì)單片機(jī)這門課。單片機(jī)這門課是一項(xiàng)非常重視動(dòng)手實(shí)踐的科目,不能總是看書,但是學(xué)習(xí)它首先必須得看書,因?yàn)閺臅心阈枰蟾帕私庖幌?,單片機(jī)的各個(gè)功能寄存器,而說(shuō)明白點(diǎn),我們使用單片機(jī)就是用軟件去控制單片機(jī)的各個(gè)功能寄存器,再說(shuō)明白點(diǎn),就是控制單片機(jī)那些管腳的電平什么時(shí)候輸出高,什么時(shí)候輸出低。由這些高低電平的變化來(lái)控制你的系統(tǒng)板,實(shí)現(xiàn)我們需要的各個(gè)功能。
至于看書,只需大概了解單片機(jī)各管腳都是干什么的?能實(shí)現(xiàn)什么樣的功能?第一次,第二次你可能看不明白,但這不要緊,因?yàn)檫€缺少實(shí)際的感觀認(rèn)識(shí)。所以我總是說(shuō),學(xué)單片機(jī)看書看兩三天的就夠了,看小說(shuō)你一天能看五六本,看單片機(jī)你兩三天看兩三遍就夠了,可以不用仔細(xì)的看。
推薦一本書,就這一本就足夠,書名是《新編MCS-51單片機(jī)應(yīng)用設(shè)計(jì)》,是哈爾濱工業(yè)大學(xué)出版社出的的,作者是張毅剛。大概了解一下書上的內(nèi)容,然后實(shí)踐,這是非常關(guān)鍵的。如果說(shuō)學(xué)單片機(jī)你不實(shí)踐那是不可能學(xué)會(huì)的,關(guān)于實(shí)踐有兩種方法你可以選擇:
方法一:你自己花錢買一塊單片機(jī)的學(xué)習(xí)板,不要求功能太全的,對(duì)于初學(xué)者來(lái)說(shuō)你買功能非常多的那種板子,上面有很多東西你這輩子都用不著,我建議有流水燈、數(shù)碼管、獨(dú)立鍵盤、矩陣鍵盤、AD或DA(原理一樣)、液晶、蜂鳴器,這就差不多了。如果上面我提到的這些,你能熟練應(yīng)用,那可以說(shuō)對(duì)于單片機(jī)方面的硬件你已經(jīng)入門了,剩下的就是自己練習(xí)設(shè)計(jì)電路,不斷的積累經(jīng)驗(yàn)。只要過(guò)了第一關(guān),后面的路就好走多了,萬(wàn)事開(kāi)頭難,大家可能都聽(tīng)過(guò)。
方法二:你身邊如果有單片機(jī)方面的高手,向他求助,讓他幫你搭個(gè)簡(jiǎn)單的最小系統(tǒng)板。對(duì)于高手來(lái)說(shuō),做個(gè)單片機(jī)的最小系統(tǒng)板只需要一分鐘的時(shí)間,而對(duì)于初學(xué)者可就難多了,因?yàn)橹挥袑?duì)硬件了解了,才能熟練運(yùn)用。而如果你身邊沒(méi)有這樣的高手,又找不到可以幫助你的人,那我勸你最好是自己買上一塊,畢竟自己有一塊要方便的多,以后做單片機(jī)類的小實(shí)驗(yàn)時(shí)都能用得上,還省事。
有了單片機(jī)學(xué)習(xí)板之后你就要多練習(xí),最好是自己有臺(tái)電腦,一天少看電影,少打游戲,把學(xué)習(xí)板和電腦連好,打開(kāi)調(diào)試軟件坐在電腦前,先學(xué)會(huì)怎么用調(diào)試軟件,然后從最簡(jiǎn)單的流水燈實(shí)驗(yàn)做起。等你能讓那八個(gè)流水燈按照你的意愿隨意流動(dòng)時(shí)你已經(jīng)入門了,你會(huì)發(fā)現(xiàn)單片機(jī)是多么迷人的東西啊,太好玩了,這不是在學(xué)習(xí)知識(shí),而是在玩。當(dāng)你編寫的程序按你的意愿實(shí)現(xiàn)時(shí),你比做什么事都開(kāi)心,你會(huì)上癮的,真的。做電子類的人真的會(huì)上癮。然后讓數(shù)碼管亮起來(lái),這兩項(xiàng)會(huì)了后,你已經(jīng)不能自拔了,你已經(jīng)開(kāi)始考慮你這輩子要走哪一行了……
就是要這樣練習(xí),在寫程序的時(shí)候你肯定會(huì)遇到很多問(wèn)題,而這時(shí)你再去翻書找,或是問(wèn)別人,當(dāng)?shù)玫浇獯鸷竽銜?huì)記住一輩子的,知識(shí)必須用于現(xiàn)實(shí)生活中,解決實(shí)際問(wèn)題,這樣才能發(fā)揮它的作用,你自己好好想想,上了這么多年大學(xué),天天上課,你在課堂上學(xué)到了什么?是不是為了期末考試而忙碌呢?考完得了90分,哈哈哈好高興啊,下學(xué)期開(kāi)學(xué)回來(lái)忘的一干二凈,是不是?你學(xué)到什么了?但是我告訴你,單片機(jī)一旦學(xué)會(huì),永遠(yuǎn)不會(huì)忘了。
另外,我再說(shuō)說(shuō)用匯編和C語(yǔ)言編程的問(wèn)題。很多同學(xué)大一二就開(kāi)設(shè)了C語(yǔ)言的課,我也上過(guò),我知道那時(shí)天天就是幾乘幾,幾加幾啊,求個(gè)階乘啊。學(xué)完了有什么用?讓你用C語(yǔ)言編單片機(jī)的程序你是不是就傻了?書上的東西我們必須要會(huì)運(yùn)用。單片機(jī)編程用C語(yǔ)言或匯編語(yǔ)言都可以,但是我建議用C語(yǔ)言比較好,如果原來(lái)有C語(yǔ)言的基礎(chǔ),那學(xué)起來(lái)會(huì)更好;如果沒(méi)有,也可以邊學(xué)單片機(jī)邊學(xué)C語(yǔ)言。
C語(yǔ)言也挺簡(jiǎn)單,只是一門工具而已,我勸你最好學(xué)會(huì),將來(lái)肯定用得著,要不你以后也得學(xué),你一點(diǎn)匯編都不會(huì)根本無(wú)所謂,但你一點(diǎn)C語(yǔ)言都不會(huì),那你將來(lái)會(huì)吃苦頭。
匯編寫程序代碼效率高,但相對(duì)難度較大,而且很羅嗦,尤其是遇到算法方面的問(wèn)題時(shí),根本是麻煩的不得了,現(xiàn)在單片機(jī)的主頻在不斷的提高,我們完全不需要那么高效率的代碼,因?yàn)橛懈哳l率的時(shí)鐘,單片機(jī)的ROM也在不斷的提高,足夠裝得下你用C語(yǔ)言寫的任何代碼,C語(yǔ)言的資料又多又好找,將來(lái)可移植性非常好,只需要變一個(gè)IO口寫個(gè)溫度傳感器的程序在哪里都能用,所以我勸大家用C語(yǔ)言。
總結(jié)上面,只要你有信心,做事能堅(jiān)持到底,有不成功不放棄的強(qiáng)烈意志,那學(xué)個(gè)單片機(jī)來(lái)說(shuō)就是件非常容易的事。
1、步驟
- 找本書大概了解一下單片機(jī)結(jié)構(gòu),大概了解就行。不用都看懂,又不讓你出書的。(三天)
- 找學(xué)習(xí)板練習(xí)編寫程序,學(xué)單片機(jī)就是練編程序,遇到不會(huì)的再問(wèn)人或查書。(二十天)
- 自己網(wǎng)上找些小電路類的資料練習(xí)設(shè)計(jì)外圍電路。焊好后自己調(diào)試,熟悉過(guò)程。(十天)
- 自己完全設(shè)計(jì)具有個(gè)人風(fēng)格的電路,產(chǎn)品……你已經(jīng)是高手了……
看到了嗎?下功夫一個(gè)多月你就能成為高手,我就講這么多了,學(xué)不學(xué)得會(huì),下不下得了功夫就看你的了。
2、我的單片機(jī)學(xué)習(xí)心得很多人說(shuō),學(xué)單片機(jī)最好先學(xué)匯編語(yǔ)言,以我的經(jīng)驗(yàn)告訴大家,絕對(duì)沒(méi)有這個(gè)必要,初學(xué)者一開(kāi)始就直接用C語(yǔ)言為單片機(jī)編程,既省時(shí)間,學(xué)起來(lái)又容易,進(jìn)步速度會(huì)很快。在剛開(kāi)始學(xué)單片機(jī)的時(shí)候,千萬(wàn)不要為了解單片機(jī)內(nèi)部結(jié)構(gòu)而浪費(fèi)時(shí)間,這樣只能打擊你的信心,當(dāng)你學(xué)會(huì)編程后,自然一步步就掌握其內(nèi)部結(jié)構(gòu)了。
單片機(jī)的學(xué)習(xí)實(shí)踐。
單片機(jī)提高重在實(shí)踐,想要學(xué)好單片機(jī),軟件編程必不可少。但是熟悉硬件對(duì)于學(xué)好單片機(jī)的也是非常重要的。如何學(xué)習(xí)好硬件,動(dòng)手實(shí)踐是必不可少的。我們可以通過(guò)自己動(dòng)手做一個(gè)自己的電子制作,通過(guò)完成它,以提高我的對(duì)一些芯片的了解和熟練運(yùn)用它。這樣我們就可以多一些了解芯片的結(jié)構(gòu)。我相信,你完成了一個(gè)屬于自己的電子制作,你的單片機(jī)水平就會(huì)有一個(gè)質(zhì)的提高。
這就是我學(xué)習(xí)單片機(jī)的心得體會(huì),希望給單片機(jī)的愛(ài)好者學(xué)好單片機(jī)有所幫助。
使用單片機(jī)就是理解單片機(jī)硬件結(jié)構(gòu),以及內(nèi)部資源的應(yīng)用,在匯編或C語(yǔ)言中學(xué)會(huì)各種功能的初始化設(shè)置,以及實(shí)現(xiàn)各種功能的程序編制。
第一步:數(shù)字I/O的使用
使用按鈕輸入信號(hào),發(fā)光二極管顯示輸出電平,就可以學(xué)習(xí)引腳的數(shù)字I/O功能,在按下某個(gè)按鈕后,某發(fā)光二極管發(fā)亮,這就是數(shù)字電路中組合邏輯的功能,雖然很簡(jiǎn)單,但是可以學(xué)習(xí)一般的單片機(jī)編程思想,例如,必須設(shè)置很多寄存器對(duì)引腳進(jìn)行初始化處理,才能使引腳具備有數(shù)字輸入和輸出輸出功能。每使用單片機(jī)的一個(gè)功能,就要對(duì)控制該功能的寄存器進(jìn)行設(shè)置,這就是單片機(jī)編程的特點(diǎn),千萬(wàn)不要怕麻煩,所有的單片機(jī)都是這樣。
第二步:定時(shí)器的使用
學(xué)會(huì)定時(shí)器的使用,就可以用單片機(jī)實(shí)現(xiàn)時(shí)序電路,時(shí)序電路的功能是強(qiáng)大的,在工業(yè)、家用電氣設(shè)備的控制中有很多應(yīng)用,例如,可以用單片機(jī)實(shí)現(xiàn)一個(gè)具有一個(gè)按鈕的樓道燈開(kāi)關(guān),該開(kāi)關(guān)在按鈕按下一次后,燈亮3分鐘后自動(dòng)滅,當(dāng)按鈕連續(xù)按下兩次后,燈常亮不滅,當(dāng)按鈕按下時(shí)間超過(guò)2s,則燈滅。數(shù)字集成電路可以實(shí)現(xiàn)時(shí)序電路,可編程邏輯器件(PLD)可以實(shí)現(xiàn)時(shí)序電路,可編程控制器(PLC)也可以實(shí)現(xiàn)時(shí)序電路,但是只有單片機(jī)實(shí)現(xiàn)起來(lái)最簡(jiǎn)單,成本最低。定時(shí)器的使用是非常重要的,邏輯加時(shí)間控制是單片機(jī)使用的基礎(chǔ)。
第三步:中斷
單片機(jī)的特點(diǎn)是一段程序反復(fù)執(zhí)行,程序中的每個(gè)指令的執(zhí)行都需要一定的執(zhí)行時(shí)間,如果程序沒(méi)有執(zhí)行到某指令,則該指令的動(dòng)作就不會(huì)發(fā)生,這樣就會(huì)耽誤很多快速發(fā)生的事情,例如,按鈕按下時(shí)的下降沿。要使單片機(jī)在程序正常運(yùn)行過(guò)程中,對(duì)快速動(dòng)作做出反應(yīng),就必須使用單片機(jī)的中斷功能,該功能就是在快速動(dòng)作發(fā)生后,單片機(jī)中斷正常運(yùn)行的程序,處理快速發(fā)生的動(dòng)作,處理完成后,在返回執(zhí)行正常的程序。
中斷功能使用中的困難是需要精確地知道什么時(shí)候不允許中斷發(fā)生(屏蔽中斷)、什么時(shí)候允許中斷發(fā)生(開(kāi)中斷),需要設(shè)置哪些寄存器才能使某種中斷起作用,中斷開(kāi)始時(shí),程序應(yīng)該干什么,中斷完成后,程序應(yīng)該干什么等等。中斷學(xué)會(huì)后,就可以編制更復(fù)雜結(jié)構(gòu)的程序,這樣的程序可以干著一件事,監(jiān)視著一件事,一旦監(jiān)視的事情發(fā)生,就中斷正在干的事情,處理監(jiān)視的事情,當(dāng)然也可以監(jiān)視多個(gè)事情,形象的比喻,中斷功能使單片機(jī)具有吃著碗里的,看著鍋里的功能。
以上三步學(xué)會(huì),就相當(dāng)于降龍十八掌武功,會(huì)了三掌了,可以勉強(qiáng)護(hù)身。
第四步:與PC機(jī)進(jìn)行RS232通信
單片機(jī)都有USART接口,特別是MSP430系列中很多型號(hào),都具有兩個(gè)USART接口。USART接口不能直接與PC機(jī)的RS232接口連接,它們之間的邏輯電平不同,需要使用一個(gè)MAX3232芯片進(jìn)行電平轉(zhuǎn)換。
USART接口的使用是非常重要的,通過(guò)該接口,可以使單片機(jī)與PC機(jī)之間交換信息,雖然RS232通信并不先進(jìn),但是對(duì)于接口的學(xué)習(xí)是非常重要的。正確使用USART接口,需要學(xué)習(xí)通信協(xié)議,PC機(jī)的RS232接口編程等等知識(shí)。試想,單片機(jī)實(shí)驗(yàn)板上的數(shù)據(jù)顯示在PC機(jī)監(jiān)視器上,而PC機(jī)的鍵盤信號(hào)可以在單片機(jī)實(shí)驗(yàn)板上得到顯示,將是多么有意思的事情啊!
第五步:學(xué)會(huì)A/D轉(zhuǎn)換
MAP430單片機(jī)帶有多通道12位A/D轉(zhuǎn)換器,通過(guò)這些A/D轉(zhuǎn)換器可以使單片機(jī)操作模擬量,顯示和檢測(cè)電壓、電流等信號(hào)。學(xué)習(xí)時(shí)注意模擬地與數(shù)字地、參考電壓、采樣時(shí)間,轉(zhuǎn)換速率,轉(zhuǎn)換誤差等概念。使用A/D轉(zhuǎn)換功能的簡(jiǎn)單的例子是設(shè)計(jì)一個(gè)電壓表。
第六步:學(xué)會(huì)PCI、I2C接口和液晶顯示器接口
這些接口的使用可以使單片機(jī)更容易連接外部設(shè)備,在擴(kuò)展單片機(jī)功能方面非常重要。
第七步:學(xué)會(huì)比較、捕捉、PWM功能
這些功能可以使單片機(jī)能夠控制電機(jī),檢測(cè)轉(zhuǎn)速信號(hào),實(shí)現(xiàn)電機(jī)調(diào)速器等控制起功能。如果以上七步都學(xué)會(huì),就可以設(shè)計(jì)一般的應(yīng)用系統(tǒng),相當(dāng)于學(xué)會(huì)十招降龍十八掌,可以出手攻擊了。
第八步:學(xué)習(xí)USB接口、TCP/IP接口、各種工業(yè)總線的硬件與軟件設(shè)計(jì)
學(xué)習(xí)USB接口、TCP/IP接口、各種工業(yè)總線的硬件與軟件設(shè)計(jì)是非常重要的,因?yàn)檫@是當(dāng)前產(chǎn)品開(kāi)發(fā)的發(fā)展方向。
到此為止,相當(dāng)于學(xué)會(huì)15招降龍十八掌,但還不到打遍天下無(wú)敵手的境界。即使如此,也算是單片機(jī)大蝦了?。?/span>
來(lái)源:網(wǎng)絡(luò)版權(quán)歸原作者所有,如有侵權(quán),請(qǐng)聯(lián)系刪除。