1.引言
還記得當(dāng)年學(xué)數(shù)學(xué)、英語(yǔ)都有個(gè)竅門,那就是搞個(gè)錯(cuò)題集。經(jīng)常復(fù)習(xí)一下這個(gè)錯(cuò)題集,就可以避免下次犯同樣的錯(cuò)誤。而幾乎所有的程序員都是從犯錯(cuò)誤開始的,我們也很有必要總結(jié)一下編程新手的常見錯(cuò)誤,本文的目的在于此。文中所列出的都是筆者在項(xiàng)目開發(fā)中接觸到的新手真實(shí)的言談,筆者學(xué)學(xué)*腔調(diào),姑且稱之為“錯(cuò)誤語(yǔ)錄”。
2.語(yǔ)錄
(1)“我的程序都是對(duì)的,可結(jié)果不對(duì)”
想想你的周圍,是不是也有人說(shuō)這樣的話?如果你也曾經(jīng)說(shuō)過(guò),那就此打住,不要再說(shuō)這句話,因?yàn)檫@句話只會(huì)顯示說(shuō)話者的無(wú)知。既然程序都是對(duì)的,那為什么結(jié)果不對(duì)?
(2)“程序=算法+數(shù)據(jù)結(jié)構(gòu)”
如果剛剛學(xué)完C語(yǔ)言,我們說(shuō)這樣的話,完全可以理解,而且可以說(shuō)是正確的。但是如果你是一位即將從事C/C++編程的程序員,那么很遺憾,這個(gè)說(shuō)法只能判錯(cuò),殊不知,世界上還有另一種說(shuō)法:
程序 = 對(duì)象 + 消息
“程序=算法+數(shù)據(jù)結(jié)構(gòu)”只對(duì)面向過(guò)程的語(yǔ)言(C)成立,而對(duì)面向?qū)ο蟮恼Z(yǔ)言(C++),則只能表述為“程序=對(duì)象+消息”。傳統(tǒng)的過(guò)程式編程語(yǔ)言以過(guò)程為中心以算法為驅(qū)動(dòng),面向?qū)ο蟮木幊陶Z(yǔ)言則以對(duì)象為中心以消息為驅(qū)動(dòng)。這里的消息是廣義的,對(duì)象A調(diào)用了對(duì)象B的成員函數(shù),可看作對(duì)象A給B發(fā)消息。
(3)“程序編出來(lái),運(yùn)行正確就行了”
運(yùn)行正確的程序并不一定是好程序,程序員時(shí)刻要牢記的一條就是自己寫的程序不僅是給自己看的,要讓別人也能輕易地看懂。很遺憾,許多的編程新手不能清晰地駕馭軟件的結(jié)構(gòu),對(duì)頭文件和實(shí)現(xiàn)文件的概念含糊不清,寫出來(lái)的程序可讀性很差。
C程序采用模塊化的編程思想,需合理地將一個(gè)很大的軟件劃分為一系列功能獨(dú)立的部分合作完成系統(tǒng)的需求,在模塊的劃分上主要依據(jù)功能。模塊由頭文件和實(shí)現(xiàn)文件組成,對(duì)頭文件和實(shí)現(xiàn)文件的正確使用方法是:
規(guī)則1 頭文件(.h)中是對(duì)于該模塊接口的聲明,接口包括該模塊提供給其它模塊調(diào)用的外部函數(shù)及外部全局變量,對(duì)這些變量和函數(shù)都需在.h中文件中冠以extern關(guān)鍵字聲明;
規(guī)則2 模塊內(nèi)的函數(shù)和全局變量需在.c文件開頭冠以static關(guān)鍵字聲明;
規(guī)則3 永遠(yuǎn)不要在.h文件中定義變量;
許多程序員對(duì)定義變量和聲明變量混淆不清,定義變量和聲明變量的區(qū)別在于定義會(huì)產(chǎn)生內(nèi)存分配的操作,是匯編階段的概念;而聲明則只是告訴包含該聲明的模塊在連接階段從其它模塊尋找外部函數(shù)和變量。如:
/*模塊1頭文件:module1.h*/
int a = 5; /* 在模塊1的.h文件中定義int a */
/*模塊1實(shí)現(xiàn)文件:module1 .c*/
#include “module1.h” /* 在模塊1中包含模塊1的.h文件 */
/*模塊2實(shí)現(xiàn)文件: module2.c*/
#include “module1.h” /* 在模塊2中包含模塊1的.h文件 */
/*模塊2 實(shí)現(xiàn)文件:module3 .c*/
#include “module1.h” /* 在模塊3中包含模塊1的.h文件 */
以上程序的結(jié)果是在模塊1、2、3中都定義了整型變量a,a在不同的模塊中對(duì)應(yīng)不同的地址單元,這明顯不符合編寫者的本意。正確的做法是:
/*模塊1頭文件:module1.h*/
extern int a; /* 在模塊1的.h文件中聲明int a */
/*模塊1實(shí)現(xiàn)文件:module1 .c*/
#include “module1.h” /* 在模塊1中包含模塊1的.h文件 */
int a = 5; /* 在模塊1的.c文件中定義int a */
/*模塊2 實(shí)現(xiàn)文件: module2 .c*/
#include “module1.h” /* 在模塊2中包含模塊1的.h文件 */
/*模塊3 實(shí)現(xiàn)文件: module3 .c*/
#include “module1.h” /* 在模塊3中包含模塊1的.h文件 */
這樣如果模塊1、2、3操作a的話,對(duì)應(yīng)的是同一片內(nèi)存單元。
規(guī)則4 如果要用其它模塊定義的變量和函數(shù),直接包含其頭文件即可。
許多程序員喜歡這樣做,當(dāng)他們要訪問(wèn)其它模塊定義的變量時(shí),他們?cè)诒灸K文件開頭添加這樣的語(yǔ)句:
extern int externVar;
拋棄這種做法吧,只要頭文件按規(guī)則1完成,某模塊要訪問(wèn)其它模塊中定義的全局變量時(shí),只要包含該模塊的頭文件即可。
還記得當(dāng)年學(xué)數(shù)學(xué)、英語(yǔ)都有個(gè)竅門,那就是搞個(gè)錯(cuò)題集。經(jīng)常復(fù)習(xí)一下這個(gè)錯(cuò)題集,就可以避免下次犯同樣的錯(cuò)誤。而幾乎所有的程序員都是從犯錯(cuò)誤開始的,我們也很有必要總結(jié)一下編程新手的常見錯(cuò)誤,本文的目的在于此。文中所列出的都是筆者在項(xiàng)目開發(fā)中接觸到的新手真實(shí)的言談,筆者學(xué)學(xué)*腔調(diào),姑且稱之為“錯(cuò)誤語(yǔ)錄”。
2.語(yǔ)錄
(1)“我的程序都是對(duì)的,可結(jié)果不對(duì)”
想想你的周圍,是不是也有人說(shuō)這樣的話?如果你也曾經(jīng)說(shuō)過(guò),那就此打住,不要再說(shuō)這句話,因?yàn)檫@句話只會(huì)顯示說(shuō)話者的無(wú)知。既然程序都是對(duì)的,那為什么結(jié)果不對(duì)?
(2)“程序=算法+數(shù)據(jù)結(jié)構(gòu)”
如果剛剛學(xué)完C語(yǔ)言,我們說(shuō)這樣的話,完全可以理解,而且可以說(shuō)是正確的。但是如果你是一位即將從事C/C++編程的程序員,那么很遺憾,這個(gè)說(shuō)法只能判錯(cuò),殊不知,世界上還有另一種說(shuō)法:
程序 = 對(duì)象 + 消息
“程序=算法+數(shù)據(jù)結(jié)構(gòu)”只對(duì)面向過(guò)程的語(yǔ)言(C)成立,而對(duì)面向?qū)ο蟮恼Z(yǔ)言(C++),則只能表述為“程序=對(duì)象+消息”。傳統(tǒng)的過(guò)程式編程語(yǔ)言以過(guò)程為中心以算法為驅(qū)動(dòng),面向?qū)ο蟮木幊陶Z(yǔ)言則以對(duì)象為中心以消息為驅(qū)動(dòng)。這里的消息是廣義的,對(duì)象A調(diào)用了對(duì)象B的成員函數(shù),可看作對(duì)象A給B發(fā)消息。
(3)“程序編出來(lái),運(yùn)行正確就行了”
運(yùn)行正確的程序并不一定是好程序,程序員時(shí)刻要牢記的一條就是自己寫的程序不僅是給自己看的,要讓別人也能輕易地看懂。很遺憾,許多的編程新手不能清晰地駕馭軟件的結(jié)構(gòu),對(duì)頭文件和實(shí)現(xiàn)文件的概念含糊不清,寫出來(lái)的程序可讀性很差。
C程序采用模塊化的編程思想,需合理地將一個(gè)很大的軟件劃分為一系列功能獨(dú)立的部分合作完成系統(tǒng)的需求,在模塊的劃分上主要依據(jù)功能。模塊由頭文件和實(shí)現(xiàn)文件組成,對(duì)頭文件和實(shí)現(xiàn)文件的正確使用方法是:
規(guī)則1 頭文件(.h)中是對(duì)于該模塊接口的聲明,接口包括該模塊提供給其它模塊調(diào)用的外部函數(shù)及外部全局變量,對(duì)這些變量和函數(shù)都需在.h中文件中冠以extern關(guān)鍵字聲明;
規(guī)則2 模塊內(nèi)的函數(shù)和全局變量需在.c文件開頭冠以static關(guān)鍵字聲明;
規(guī)則3 永遠(yuǎn)不要在.h文件中定義變量;
許多程序員對(duì)定義變量和聲明變量混淆不清,定義變量和聲明變量的區(qū)別在于定義會(huì)產(chǎn)生內(nèi)存分配的操作,是匯編階段的概念;而聲明則只是告訴包含該聲明的模塊在連接階段從其它模塊尋找外部函數(shù)和變量。如:
/*模塊1頭文件:module1.h*/
int a = 5; /* 在模塊1的.h文件中定義int a */
/*模塊1實(shí)現(xiàn)文件:module1 .c*/
#include “module1.h” /* 在模塊1中包含模塊1的.h文件 */
/*模塊2實(shí)現(xiàn)文件: module2.c*/
#include “module1.h” /* 在模塊2中包含模塊1的.h文件 */
/*模塊2 實(shí)現(xiàn)文件:module3 .c*/
#include “module1.h” /* 在模塊3中包含模塊1的.h文件 */
以上程序的結(jié)果是在模塊1、2、3中都定義了整型變量a,a在不同的模塊中對(duì)應(yīng)不同的地址單元,這明顯不符合編寫者的本意。正確的做法是:
/*模塊1頭文件:module1.h*/
extern int a; /* 在模塊1的.h文件中聲明int a */
/*模塊1實(shí)現(xiàn)文件:module1 .c*/
#include “module1.h” /* 在模塊1中包含模塊1的.h文件 */
int a = 5; /* 在模塊1的.c文件中定義int a */
/*模塊2 實(shí)現(xiàn)文件: module2 .c*/
#include “module1.h” /* 在模塊2中包含模塊1的.h文件 */
/*模塊3 實(shí)現(xiàn)文件: module3 .c*/
#include “module1.h” /* 在模塊3中包含模塊1的.h文件 */
這樣如果模塊1、2、3操作a的話,對(duì)應(yīng)的是同一片內(nèi)存單元。
規(guī)則4 如果要用其它模塊定義的變量和函數(shù),直接包含其頭文件即可。
許多程序員喜歡這樣做,當(dāng)他們要訪問(wèn)其它模塊定義的變量時(shí),他們?cè)诒灸K文件開頭添加這樣的語(yǔ)句:
extern int externVar;
拋棄這種做法吧,只要頭文件按規(guī)則1完成,某模塊要訪問(wèn)其它模塊中定義的全局變量時(shí),只要包含該模塊的頭文件即可。