官术网_书友最值得收藏!

  • C語言程序設計
  • 姚嵩
  • 4740字
  • 2021-01-18 11:06:18

1.5 程序開發過程

本節討論程序開發過程,包括程序調試(Testing)和排除錯誤(簡稱排誤,Debugging)等方面的問題。調試和排誤是程序實現的必經階段。在讀者剛開始學習程序設計時,下面討論的一些情況可能難以完全明白,因為還缺乏程序設計實踐,但是這些問題確實需要說明。本書把有關討論集中在這里,希望讀者能在學習了后面章節、做了些程序后再回來重讀這些說明,這樣反復幾次就能弄清楚了。

1.5.1 程序的開發過程

用計算機解決問題的過程可以用圖1-4描述,這種過程大致如下。

(1)分析問題,設計一種解決問題的途徑。

(2)根據所設想的解決方案,用編輯系統(或IDE)建立程序。

(3)用編譯程序對源程序進行編譯。正確完成就進入下一步;如發現錯誤,就需要設法確定錯誤,返回到第(2)步去修改程序。

(4)反復工作直到編譯能正確完成,編譯中發現的錯誤都已排除,所有警告信息都已處理(其中一些排除,其余已弄清不是錯誤),這時就可以做程序連接了。如果連接發現錯誤,就需返回前面步驟,修改程序后重新編譯。

圖1-4 程序開發過程

(5)正常連接產生了可執行程序后,就可以開始程序的調試執行了。此時需要用一些實際數據來考查程序的執行效果。如果執行中出了問題或發現結果不正確,那么就要設法確定錯誤原因,返回到前面步驟:修改程序、重新編譯、重新連接,等等。

1.5.2 程序錯誤

關于排除程序錯誤的術語“Debugging”還有一個故事。在計算機發展早期的美國,有一天,一臺計算機出故障不能運行了。經仔細檢查,人們發現計算機里有一個被電流燒焦的小蟲(bug),它造成了電路短路,是這次故障的禍根。從此,檢查排除計算機故障的工作就被稱為“Debugging”,就是“找蟲子”。后來人們也這樣看待和稱呼檢查程序錯誤的工作。

實際上,對程序設計而言這個詞并不貼切。因為程序中的錯誤都是編程者所犯的錯誤,并沒有其他客觀原因,也沒有蟲子之類的小東西搗亂,學習程序設計首先應該認清這一情況。所謂排除程序錯誤,也就是排除自己在程序設計過程中所犯的錯誤,或說是改正自己寫在程序里的錯誤。初學者在遇到程序問題時,往往傾向于認為所用系統或者計算機有問題,常會說“我的程序絕沒有錯,一定是系統的毛病”。而有經驗的程序員都知道,如果程序出了錯,基本上可以肯定是自己的錯,需要仔細檢查程序去排除它們。

程序的錯誤可以分為兩大類,一類是程序書寫形式在某些方面不符合程序語言要求而形成的錯誤。對于這類錯誤,語言系統在加工程序的過程中能夠檢查出來。另一類是程序書寫形式本身沒錯,加工過程能正常完成,產生可執行程序,但或是程序執行中出了問題或是計算結果(或執行效果)不符合需要的錯誤。排除程序錯誤的目的就是要消除這兩類錯誤。

1.5.3 程序加工中有關錯誤的排除

如果語言系統在程序加工過程中能查出錯誤,編譯程序或連接程序就會產生出錯信息。

通常,語言處理程序每發現一個錯誤就產生一個錯誤信息行,指明發現錯誤的位置(例如發現錯誤的源程序行編號等)和所確認的錯誤類型,信息行里還可能包括其他信息,供人們檢查程序時參考。不同的C語言系統在檢查錯誤的能力、產生出錯信息的形式等方面可能有許多不同,但無論如何,每當系統給出了出錯信息,人們都應該仔細閱讀,檢查錯誤信息所指定位置附近的源程序代碼,找到真正的錯誤原因并予以排除,然后再繼續下去。

編譯程序能發現的錯誤(編譯錯誤)主要有兩類。

(1)局部語法錯誤,如缺少必要的符號(常見的如缺少分號、括號),組合符號拼寫不正確等。對這些錯誤,編譯程序都能給出發現錯誤的位置,但給出的錯誤原因有時未必正確。編譯程序是一個個字符地檢查源程序,如果檢查到某位置能確定程序有問題,就把這里作為發現錯誤的位置。因此,源程序中實際錯誤或是出現在編譯程序指定的出錯位置或是在這個位置之前,應當從這里開始向前檢查,設法確定錯誤原因。有些錯誤可能到很遠以后才被編譯程序發現,也就是說,實際錯誤可能出現在編譯程序所指位置前面很遠的地方。還有一個問題值得注意,有時一個實際錯誤會導致編譯程序產生許多出錯信息行,這是因為源程序錯誤可能使編譯程序進入某種非正常的狀態,致使它產生一系列出錯信息。經驗告訴人們,排除程序錯誤的基本原則是:每次編譯后集中精力排除編譯程序發現的第一個錯誤,如果無法確認后面的錯誤,就應當重新編譯檢查。排除一個錯誤可能消除掉許多出錯信息行。

(2)程序里上下文關系方面的錯誤。程序里的許多東西有前后對應問題,例如要用的東西必須先有定義,如果編譯過程中發現某些東西無定義,就會指出這個錯誤。這種錯誤通常是因為名字拼寫有誤而造成的,或者有時確實是忘記定義了,這些都比較容易檢查和糾正。

編譯程序發現錯誤時總能提供出錯位置的信息,這種信息非常重要。為幫助人們發現程序中的問題,許多編譯程序還做一些超出語言定義的檢查,如果發現程序有可疑之處,它會提供警告信息(warning)。這種信息未必表示程序有錯誤,但也很可能是真有錯誤。經驗告訴我們,對警告信息絕不能掉以輕心,警告常常預示著隱藏較深的錯誤,必須認真地一個個弄清其原因,只有那些能確認沒有問題的警告,才可以讓它們留在那里。

連接程序也可能檢查出一些錯誤,這些錯誤稱為連接錯誤。連接錯誤都是有關目標模塊間或目標模塊與程序庫、運行系統之間關系方面的問題。例如,若在前面簡單程序里不慎把“main”寫成“mian”,編譯時不會發現問題,連接時會得到一個錯誤信息,意思是說連接中沒找到名字為“main”的函數。出問題的原因是C程序運行系統要用這個函數去啟動程序,而在程序里沒有這個函數(因為名字寫錯了)。連接程序發現的錯誤通常都與名字有關,此時它只能指出發現了關于哪個名字的錯誤,卻無法指出有關錯誤在源程序里出現的位置。對于小程序,這種錯誤很容易排除,程序大時可以利用編輯器的字符串查找功能來排除。

1.5.4 程序運行中的錯誤

完成了程序加工,生成了可執行程序之后,下一步工作應是試驗性地運行程序了。檢查運行情況,看它是否正確實現了所需功能。程序運行中也可能會出錯,出錯情況可能有多種。

(1)程序執行中可能違反了系統環境的基本要求,例如試圖執行某種非法操作。這時會出什么問題完全由程序及其運行所在的操作系統決定。在檢查嚴格的系統里,這種程序通常會因為違規而被強行終止,操作系統可能給出出錯信息;在控制不嚴或者完全沒控制的系統(例如計算機的DOS 系統)里,程序的這種問題多半會導致系統死機或出現其他不正常現象。這種程序錯誤往往很隱蔽,需要仔細檢查才能發現。在寫C程序時不注意,就容易寫出這種錯誤程序,這是C語言的一個重要缺點。在本書后面的討論中,也特別注意提醒讀者在哪些地方需要小心。

(2)由于編程錯誤,致使程序在執行中進入某種不能結束的狀態,一般稱“進入死循環”,也就是無休止地重復執行某段指令而無法停止。這種程序在啟動后長時間沒有反應,或是在執行中不斷輸出類似信息(如果死循環里有輸出命令)。當然,長時間無反應未必說明程序進入了死循環。如果程序里要求鍵盤輸入,執行到達這里程序就會進入等待,直到由鍵盤輸入信息后才繼續下去,這是正常情況,另一方面,有的程序確實需要運行較長時間。對程序是不是真正進入了死循環,還需要仔細分析和判斷。

(3)程序在執行中因為出現某些情況無法繼續下去而停止,這時會給出運行中的動態錯誤信息。例如算術運算中把0作為除數,這將使程序無法繼續執行,只能停止。

(4)還有一種情況:程序能執行到結束,并不出錯,但是產生的結果卻不合要求或者不正確。這種錯誤屬于一般性的語義錯誤,也是程序編制方面的問題。

編程中出錯是常見問題,調試和排除錯誤是程序設計(開發)過程中必需的工作階段。

1.5.5 動態運行錯誤的排除

人們常把程序錯誤分為兩類。一類是靜態錯誤,通過靜態檢查源程序可以清楚地看到它們。編譯程序、連接程序能發現的錯誤都屬于這一類。系統在加工中發現錯誤給出信息后,比較容易通過檢查有關位置的上下文,確定錯誤原因和改正方法。要想找出這種錯誤,需要熟悉C語言的規定,包括各種結構形式和上下文關系方面的規定等。

另一類稱為動態運行錯誤,出現在程序執行中,確認和糾正都更困難。僅能從程序代碼、數據情況與得到的結果去設法弄清原因,需要更多的分析和思考。在發現動態運行錯誤后,首先還是應該分析錯誤的現象和程序代碼,考慮出現錯誤的可能性,逐步排除疑點。

在發現程序錯誤疑點后,應該通過適當選擇試驗運行中提供的數據,設法確認所作出的判斷,還可以設法找出導致錯誤產生的最簡單數據。經過一系列試驗和仔細分析,簡單程序中的大部分錯誤都可能直接確認和排除。

如果無法直接確定錯誤原因,那么就需要采用動態檢查技術了。進行動態錯誤檢查的基本方法是檢查程序執行的中間過程(中間狀態)。人們最常用的一種方式是在有疑問的地方插入一些輸出語句,讓程序在執行中輸出一些變量的值,通過檢查關鍵變量的變化情況,常常可以發現導致程序錯誤的線索。

C語言系統通常都為程序的動態檢查提供了支持。尤其是各種集成式開發環境,它們都為程序的動態檢查提供了強有力的支持。這方面的功能通常包括追蹤、監視、設置斷點、中斷執行等,在以調試方式執行程序時可以使用這些功能,這里做些簡單介紹。

(1)追蹤。一般程序執行是通過一個啟動命令,程序啟動后就無約束地自動進行直至結束(可能是被強行終止或是自己終止)或進入死循環。對程序進行追蹤指的是以有控制的方式執行程序,例如要求它一個一個語句地執行(單步執行)或要求它執行到某處暫時停下來(中斷執行)等。這樣就可以通過各種方式檢查程序的中間狀態,以便發現錯誤的根源。目前各種集成開發環境都提供了許多追蹤及檢查功能。

(2)監視。指在程序追蹤過程中始終關注程序里某些變量的變化情況。

(3)設置斷點。在開始追蹤前,可以在程序里標出一些位置,要求程序執行到這些位置時停下來,以便做進一步檢查。程序在斷點暫停后,可以按命令繼續執行下去或從執行中退出。如果確實發現錯誤,顯然應該讓程序停下來,修改后重新編譯。

(4)中斷執行。當發現(或認為)程序進入了非正常狀態或在程序執行中需要檢查中間狀態時,可以中斷程序執行。在調試中可以給程序發中斷命令,程序接到中斷命令后就會停在當時的執行點,但還處于執行狀態。這樣就可以檢查執行現場的各種情況。

強有力的集成開發環境對編程而言確實是一個好條件。在學習程序設計的過程中,逐步了解和掌握所用工具也非常重要。目前有很多商用的集成開發環境,計算機上的語言系統一般都以這種環境作為主要部分。不同開發環境雖然各有特點,但在對程序開發和調試的支持方面差別不大,掌握一個就可以觸類旁通,學習使用其他系統時也不會遇到很大困難。

人們應當看到,再好的集成開發環境也只是一個好工具,正確熟練地使用它們,能幫助編程者發現程序錯誤的線索,但確認和改正錯誤則必須依靠人動腦動手。因此,不能因為有了集成開發環境就不注意程序的寫法了。人們在程序設計的實踐中認識到,良好、正確的編程習慣和方式是至關重要、不可替代的。

人們也應看到事物的另一面:好的集成開發環境并不能造就優秀的程序工作者。現在的程序開發環境功能越來越強大,但我們卻常能看到許多用高級工具編出的程序質量很差。編好程序最重要的還是要有對這一工作過程中的規律性的理解以及相當的程序設計經驗。程序并不是代碼的堆積,編程中最重要的一個方面是程序的設計和組織,程序越大,這方面工作的地位和作用就越明顯。本書后面還要通過討論和例子反復強調這一問題。

關于調試,還有一個重要問題。荷蘭計算機科學家(圖靈獎獲得者)Dijkstra 有一句名言:“調試可以確認一個程序里有錯誤,但是不能確認其中沒有錯誤。”一個程序是否正確,這是一個非常深刻的、很難回答的問題。關于這個問題,既有許多理論研究也有許多實際的方法研究。在進入程序設計這個世界之前,請大家首先記住這一點。

主站蜘蛛池模板: 交口县| 芒康县| 涞水县| 崇左市| 当阳市| 淮滨县| 太湖县| 通江县| 万源市| 高台县| 略阳县| 砀山县| 吉安县| 太康县| 广南县| 牟定县| 博湖县| 米泉市| 石棉县| 道真| 象山县| 盘锦市| 金塔县| 台东市| 柳州市| 杭锦旗| 怀集县| 巴彦县| 巴林右旗| 抚宁县| 怀化市| 乌拉特中旗| 牟定县| 论坛| 灵宝市| 电白县| 武乡县| 阜新市| 民丰县| 上饶市| 朝阳县|