《程式設計實踐(評註版)》是一本(美)凱尼漢(Kernighan,B.W.),(美)派克(Pike,R.)編制,在2011年出版的書籍。
基本介紹
- 書名:程式設計實踐(評註版)
- 作者:(美)凱尼漢(Kernighan,B.W.),(美)派克(Pike,R.)
- 譯者:白喬評 注
- ISBN:978-7-121-13458-6
- 頁數:329
- 定價:59.00元
- 出版社:電子工業出版社
- 出版時間:2011年6月
- 開本:16開
內 容 簡 介,評註者序,前 言,目 錄,
內 容 簡 介
The Practice of Programming針對程式設計過程中的風格、算法與數據結構、設計與實現、界面、除錯、測試、性 能、可移植性、記法等各個方面,系統地討論了一些常見問題和實用技巧。通過對本書的學習,讀者可以快速掌握程式 設計的技巧及思想。
本評註版力邀國內資深專家執筆,在英文原著基礎上增加中文點評與注釋,旨在融合二者之長,既保留經典的原創 文字與味道,又以先行者的學研心得與實踐感悟,對讀者閱讀與學習加以點撥、指明捷徑。
評註者序
程式設計師的一生(武林大俠的人生貌似也是如此)往往都是在激情和 迷惘兩種狀態之間來回切換。當我們接觸到一些新的東西(新的編程語 言、新的語法特性、新的協定工具,等等)時,就會急切地想去了解它、 掌握它,會坐在心愛的計算機前,廢寢忘食、夜以繼日地反覆實踐。可是 當我們的實踐達到一定的程度時,往往又會陷入另外一種狀態——覺得很 迷惘。一方面感覺自己學習的那點編程技巧已經足夠,足以應付一些實際 的項目。但另一方面又會在實戰過程中隱隱地感覺到有些問題存在:代碼 寫得總是有點醜陋、運行效率總是比想像中的要慢一些、和其他程式模組 互動起來總是存在著一些彆扭、一些莫名其妙的錯誤總是會在一些不恰 當的時候出現,你無法自信地告訴用戶你的程式真的很棒,如果將它從 Windows下移植到Linux下,你甚至不知道會有什麼問題……你明明意識到 了這些問題,卻苦於無法去改進,教科書中的每一句話早已爛熟於心,卻 絲毫找不到問題的答案,和程式設計師前輩討論的時候,也只會得到一些只言 片語,總不 能找到一套系統的修煉之道——針對這種情況,你要做的就是 尋找一些能針對實際問題對症下藥的讀本,而The Practice of Programming 就是這樣的一本書。
The Practice of Programming 由Kernighan和Pike編著,成書於上個世紀
(1999年)。年代看似有些久遠,但該書討論的是一些很難過時的話題, 就像我們今天還在討論2000多年前“孔孟之道”和“孫子兵法”一樣,12 年後的今天,我們再次讀起The Practice of Programming ,仍沒有感覺到一 絲腐朽的氣味。從內容上看,該書幾乎囊括了程式設計師深有感觸的各種問題,對於很多彷徨的程式設計師來說,這絕對是一貼切中要害的良藥。全書主 要採用C++/Java作為範例語言,但絲毫不影響其他語言的愛好者以此作為 升級讀本。
全書分成9章,分別是:
Chapter 1: Style(風格)
指導你如何寫出優雅的代碼,而不是亂寫一氣。
Chapter 2: Algorithms and Data Structures(算法與數據結構) 總結一下各種基本的算法和數據結構。
Chapter 3: Design and Implementation(設計與實現) 緊接第2章,用5種不同的語言討論具體的程式實現。
Chapter 4: Interfaces(界面) 展示了用戶和程式之間、程式模組之間應有的界面設計。
Chapter 5: Debugging(除錯) 系統地討論了除錯的各種策略和技巧。
Chapter 6: Testing(測試) 指導如何手動地、自動地進行程式的測試,以保證程式能正常工作。
Chapter 7: Performance(性能) 循序漸進,演示如何通過不斷的重構最佳化程式的性能。
Chapter 8: Portability(可移植性) 討論提高程式的可移植性所關注的地方和可用的技巧。
Chapter 9: Notation(記法) 討論如何採用一些有用的記法簡化程式,將數據和邏輯用合適的記法表達出來。
很 多 程 序 員 很 享 受 閱 讀 英 文 原 著 , 從 某 種 角 度 來 說 , 英 文 更 能 確 切表達計算機世界的概念,如同樣是“註解”、“注釋”,comment和 a n n o t a t i o n 在程式設計世界中就具有不同的含義。有些辭彙一旦做了翻 譯,如object、list、map、foreach等,反倒會讓國內讀者感受到莫名的障 礙,程式設計師彼此交流時,有的時候就乾脆直接採用英文說法。再如一些 縮寫,如CSV格式,它來源於Comma-Separated Values(“以逗號分隔的 值”),原義極其樸素,但縮寫成CSV就顯得太過高深。同樣的例子還有 internationalization和localization,它們常被縮寫成I18N和L10N,如果拋開英文原詞,就會多一些神秘感。再如:“Abort, Retry, Fail?”這是作業系統 中常常列印出來的一句原話,如果再翻譯成中文,就失去了原有上下文的 意味。閱讀英文原版的另外一個好處,還在於當我們看到memset()函式時 就會聯想到memory set,看到strcpy()函式時就會聯想到string copy。
The Practice of Programming 用語淺顯易懂,深入淺出,但由於文化的 差異,在為避免讀者理解上的困難,有些地方我們在保留原汁原味的同 時,還增加了一些本地化的註解。註解的比例大概為20%左右,通過附上 些親切的中文用以強調、擴展作者提出的某些概念和觀點,以避免讀者迷 失在英文詞句的汪洋大海中,一去不復返。
在評註過程中,由於學識有限,為避免一面之辭,評註者大量參考了
C++ ISO標準、網際網路資料與國內的一些計算機教材,也包括裘宗燕老師
2007年針對The Practice of Programming 的譯本,力求在術語使用和觀點解 釋上,不會給國內程式設計師造成任何誤解。最後感謝電子工業出版社的張春
雨先生及其他同事,是你們的辛勤勞動促成了這本評註版得以與廣大程式 員見面。
正如作者所強調的,程式設計並沒有編碼那么簡單,它是一項高技巧 的腦力勞動。悲慘的是,程式設計被很多的人“演繹”成、也被更多的人 “曲解”成毫無技巧樂趣可言的體力勞動!我們看到千千萬萬的準“程式 員”,進入某個軟體工廠,僅僅通過幾個月的培訓,就被製造成能夠“勝 任”的程式設計師,在這裡,他們被灌輸的僅僅是規則的遵守和他人代碼的機 械模仿,留給他們的思考和設計的空間極其有限。失去了思維的權利的程 序員,在隨後的人生中不得不在各種各樣的崗位上按照他人的意願做著一 次又一次的重複的機械式的工作,很多的程式設計師也因為興趣問題放棄了程 序設計,轉向其他的職業生涯。殊不知,程式設計的世界是其樂無窮的, 是無止境的,它需要永久的激情 和持續的實踐積累。評註者真心期望讀者 朋友們能從閱讀本書的過程中得到收穫,得到心靈上的升華。唯有那些有 思想的程式設計師,方能寫出有靈魂的代碼。
2011.4 北京
前 言
你是否曾經……
花費了太多的時間去對一個本來就錯誤的算法做編碼實現? 使用了一個超級複雜的數據結構? 測試一個程式,卻忽視了其中極其明顯的問題? 花整天的工夫來查找一個其實只需要5分鐘的bug? 需要讓一個程式運行速度快3倍並且要使用更少的記憶體? 耗費心機地把一個程式從工作站移到PC上,或者反過來? 試圖對其他人寫的某個程式做個適度的修改? 因為根本無法理解一個程式,你乾脆就重寫了它? 這是不是很有趣?
這樣的事情每時每刻都在程式設計師身上發生。處理這些事情往往要比想 象的困難得多。其原因就在於:常規的計算機科學和程式設計課程都不大 關注那些諸如測試、除錯、可移植性、性能、設計以及風格等程式設計實 踐方面的話題。大部分程式設計師可能會隨著自己經驗的增長無計畫地學到一 些東西,但也有些人,他們始終都不會學到這些東西。
當人們面對著那些極度複雜的界面、不斷變化的工具、語言與系統, 以及來自於其他事情的無情壓力的時候,往往很容易忘掉某些基本的法 則,即簡單、清晰與普適,事實上正是這些法則構成好的軟體的基礎。人 們也會忽略工具和記法的效用,實際上,利用它們可以讓計算機自動構造 出某些軟體,從而讓計算機專心致力於真正的程式設計。
本書提出的一些方法,正是基於這些適用於計算的各個層次的潛在 的、互相關聯的法則而成。這些方法包括:簡單化,它能使程式簡短且易於管理;清晰化,它保證無論是人還是機器都能很好地理解程式;普適 化,它意味著程式在很多種情形下都能很好地工作,當新的情況出現時, 也能很好地調整;自動化,讓計算機幫我們做一些工作,從而使我們從瑣 事中解脫出來。通過考察各種不同語言中的程式設計,我們從算法、數據 結構到設計、調試、除錯、測試和性能改進,闡述了一些具有普遍意義 的,且獨立於語言、作業系統和編程範式的工程化概念。
本書提煉於我們多年的軟體開發和維護、程式設計課程的教學以及 與各種各樣的程式設計師共同工作的經歷。我們希望與大家共享這其中的經驗 和教訓,從我們的實踐中有所感悟。其中向各層次的程式設計師給出了一些建 議,以使大家的工作變得更加嫻熟、高效。
本書適用於不同類型的讀者。如果你是一名學生,已經上過一兩門程 序設計課程,希望成為一個更好的程式設計師,這本書將為你展開一些在課堂 里只能做有限的討論的某些話題。如果你把編程作為自己的一部分任務, 而非你工作的全部,這些 信息將幫助你快速有效地寫出程式。如果你是職 業程式設計師,在學校期間沒有學過這些內容,或者希望藉此溫習一下,或者 你是個軟體管理者,希望你的員工得到指導而有所進步,那么這裡提供的 材料都會是很有價值的。
我們希望這裡給出的建議能夠幫助人們寫出更好的程式。對你唯一有 要求的前提條件就是,你已經做過一些程式設計,而且最好是用C、C++ 或者Java語言。當然,已有的經驗越多,就會越容易——但也無法做到讓 你在21天內從新手變成專家
較之那些經常用Windows和Macintosh的程 序員,UNIX和Linux的程式設計師可能會覺得本書的一些例子更為熟悉一點。 但是不管你來自哪個環境,程式設計師都該找點東西,讓生活過得更為舒坦一 些。
相反,在這之前,市場上充斥著各種《21天教程》,名字比較誘人,但估計 連作者自己也不敢相信誰能夠真的在21天內學完這些東西。
本書分成9章,每一章關注程式設計實踐的一個方面。 第1章討論程式設計風格。好的風格對於好的程式設計極其重要,因此
我們放在最前面討論。書寫良好的程式總比亂寫一氣的程式好——它們包
含的錯誤更少,更容易除錯,也更易於修改。因此從一開始就注意風格這 尤為重要。這一章還介紹了良好程式設計的一個重要主題,即儘量採用編 程語言的習慣用法。
第2章討論算法和數據結構,這是計算機科學必修課的核心內容,也是 程式設計課程的重要組成部分。鑒於許多讀者已經熟悉了這方面的內容, 我們對那些幾乎出現在每個程式里的算法和數據結構做了一個簡單的回 顧。更複雜的算法和數據結構通常都是由這些基本東西構建起來的,因此 需要掌握好這些基礎。
第3章討論了一個小程式的設計,通過該程式展示實戰環境中算法與數 據結構的問題。該程式採用5種不同的語言實現,通過比較這些不同的實現 版本,我們不難發現相同的數據結構如何在不同語言裡來進行處理,以及 不同語言在表達能力和性能方面之間的差異等。
用戶和程式之間、程式不同部分之間的界面是程式設計的基本問題。 軟體的成功很大程度上取決於良好的界面設計和實現。第4章展示了一個 小函式館的不斷演化過程,該函式用以解析一種通用的數據格式。雖然這 個例子很小,但卻能展現出界面設計的許多重要問題,諸如抽象、信息隱 蔽、資源管理和錯誤處理,等等。
雖然我們總希望一次就能把程式寫正確,但是,bug以及由之帶來的除 錯,實際上是無法避免的。第5章討論了一些系統化的、有效的除錯策略與 技巧。在這些話題中,讀者可以看到常見的bug,以及數值規律的重要性: 除錯輸出中某些模式性的東西往往能告訴我們哪裡出了問題。
測試的目的就是試圖給出一種合理的保證,以證明一個程式是在正常 地工作,或者說它經過改造之後還是正常的。第6章強調如何通過手工和機 械的方式進行系統化的測試。邊界條件測試往往布置在那些潛在的薄弱點 上。機械化和測試台會使得測試事半功倍。壓力測試提供了一種非常人能 用的方法進行的另一類測試,它能找出另外一些錯誤。
今天的計算機,其速度已經足夠快了,編譯器做得也是足夠好的,因 此,許多程式在寫出之時就已經足夠快。但是,另一些程式還是慢,或者 耗費了太多的記憶體,或者二者兼而有之。第7章給出了一種有序的方法, 以使程式能更有效地使用資源,並在提高效率的同時仍然保持原先的正確 性。
第 8章涵蓋了可移植性問題。對於成功的程式來說,當環境發生了變 化,或者需要移植到新的系統、新的硬體,甚至新的國家時,它們仍會正 常工作足夠長的時間。可移植性的目標就是減少程式移植到新環境下所必 需的變動,藉此降低程式的維護成本。
今天的計算語言已經相當豐富了,除了我們常用來做程式設計的通用 語言,還有許多套用在較窄領域中的專用語言。第9章給出了一些例子,說 明在計算領域裡記法的重要性,並說明如何採用它來簡化程式、指導程式 實現,或者幫助我們編寫那種能夠寫程式的程式。
由於討論到程式設計,我們不得不貼出很多代碼。其中大部分的例子 是為本書特意準備的,也有些小例子改編自其他來源。為了把這些代碼寫 好,我們花了很大的功夫,並且在半打的作業系統上測試過這些代碼的機 器碼。
本書里的大部分程式都是基於C語言的,也有一些用C++或Java寫的程 序例子,還有關於腳本語言的簡單展開。C和C++在低層次上幾乎是完全一 樣的,因此我們給出的C程式往往也是合法的C++程式。C++和Java作為C 語言的直系後代,它們繼承的遠不止一些語法,更多的 是其效率和表達能 力,同時增加了更為豐富的類型和函式館。
在我們自己的工作中,經常會用到這三種語言,當然也有一些其他 的語言。語言的選擇取決於:作業系統最好用某種高效的、不受限制的語 言,如C或者C++;快速原型通常採用某個命令解釋器或者腳本語言,比如 Awk或Perl;對於用戶界面,Visual Basic或Tcl/Tk,還有Java,都是有力的 候選者。
對於我們的例子,語言的選擇上還有一個重要的教學因素。正如沒有 一種語言能夠解決所有問題一樣,也沒有哪一種語言能夠很好地演繹出所 有的話題。高級語言往往暗含了某種設計策略的選擇。如果用低級語言, 我們將能全面地討論問題的各種解答,揭示其中更多的細節,討論的效果 會更好。經驗證明,即使是在使用高級語言的功能時,了解它們與低級問 題之間的關係也是很有意義的。如果沒有這種深入的觀察,我們就很容易 陷入到性能或者某種奇怪的行為當中。因此,我們常常採用C語言作為例 子,即便 是實際環境下我們會採用其他的語言。
不過,本書大部分的內容其教程還是獨立於任何特定程式設計語言的。 數據結構的選擇受到所使用語言的影響,在有些語言裡這種選擇會少些,在 另外一些語言裡則會多些。但是如何來選擇,其方法其實是一樣的。在不同 語言裡,如何做測試和排錯都會有所差異,但其策略和技巧也是類似的。一 言以蔽之,改進程式效率的大部分技術都可套用到任何語言。
作為一名程式設計師,不管是採用什麼語言寫程式,你的工作都是如何 利用手頭的工具,儘可能地把事情做好。一個優秀的程式設計師可以克服由 一種不夠強大的語言或者一個簡陋的作業系統所帶來的缺陷,反之,即 使是一個超級棒的程式設計環境,也沒法幫一個糟糕的程式設計師的忙。我 們希望無論你現在的經驗和技巧如何,這本書都將幫助你更好地做程式 設計並享受之。
衷心感謝所有那些讀過書稿並給予幫助性的建議的朋友和同事。Jon Bentley,Russ Cox,John Lakos,John Linderman,Peter Memishian,lan Lance Taylor,Howard Trickey和 Chris Van Wyk極其細緻地通讀了本書的手 稿,一遍甚至數遍。
感謝Tom Cargill,Chris Cleeland,Steve Dewhurst,Eric Grosse, Andrew Herron,Gerard Holzmann,Doug McIlroy,Paul McNamee, Peter Nelson,Dennis Ritchie,Rich Stevens,Tom Szymanski,Kentaro Toyama,John Wait,Daniel C. Wang,Peter Weinberger,Margaret Wright 和 Cliff Young,他們對手稿的各個方面提出了極有價值的意見。我們也感 謝A1 Aho,Ken Arnold,Chuck Bigelow,Joshua Bloch,Bill Coughran, Bob Flandrena,Renee French,Mark Kernighan, Andy Koenig,Sape Mullender,Evi Nemeth,Marty Rabinowitz,Mark V. Shaney,Bjarne Stroustrup, Ken Thompson和Phil Wadler,感謝你們給予的忠告和成熟的建議,謝謝你們。
Brian W. Kernighan
Rob Pike
目 錄
前言(新增批註共1條)
Chapter 1: Style(新增批註共46條) xii
1
1.1 Names 3
1.2 Expressions and Statements 7
1.3 Consistency and Idioms 13
1.4 Function Macros 21
1.5 Magic Numbers 23
1.6 Comments 28
1.7 Why Bother? 35
Chapter 2: Algorithms and Data Structures(新增批註共29條)
37
2.1 Searching 38
2.2 Sorting 41
2.3 Libraries 44
2.4 A Java Quicksort 48
2.5 O-Notation 52
2.6 Growing Arrays 54
2.7 Lists 57
2.8 Trees 64
2.9 Hash Tables 70
2.10 Summary 74
Chapter 3: Design and Implementation(新增批註共12條)
76
3.1 The Markov Chain Algorithm 77
3.2 Data Structure Alternatives 79
3.3 Building the Data Structure in C 81
3.4 Generating Output 85
3.5 Java 89
3.6 C++ 93
3.7 Awk andPerl 97
3.8 Performance 99
3.9 Lessons 101
Chapter 4: Interfaces(新增批註共20條) 104
4.1 Comma-Separated Values 105
4.2 A Prototype Library 107
4.3 A Library for Others 111
4.4 A C++ Implementation 121
4.5 Interface Principles 126
4.6 Resource Management 130
4.7 Abort, Retry, Fail? 135
4.8 User Interfaces 140
Chapter 5: Debugging(新增批註共28條) 144
5.1 Debuggers 146
5.2 Good Clues, Easy Bugs 148
5.3 No Clues, Hard Bugs 153
5.4 Last Resorts 160
5.5 Non-reproducible Bugs 164
5.6 Debugging Tools 166
5.7 Other People’s Bugs 169
5.8 Summary 171
Chapter 6: Testing(新增批註共28條) 173
6.1 Test as You Write the Code 174
6.2 Systematic Testing 181
6.3 Test Automation 186
6.4 Test Scaffolds 189
6.5 Stress Tests 193
6.6 Tips for Testing 197
6.7 Who Does the Testing? 199
6.8 Testing the Markov Program 200
6.9 Summary 202
Chapter 7: Performance(新增批註共30條) 204
7.1 A Bottleneck 205
7.2 Timing and Profiling
211
7.3 Strategies for Speed 217
7.4 Tuning the Code 221
7.5 Space Efficiency 228
7.6 Estimation 231
7.7 Summary 234
Chapter 8: Portability(新增批註共30條) 236
8.1 Language 237
8.2 Headers and Libraries 245
8.3 Program Organization 247
8.4 Isolation 252
8.5 Data Exchange 254
8.6 Byte Order 256
8.7 Portability and Upgrade 259
8.8 Internationalization 262
8.9 Summary 266
Chapter 9: Notation(新增批註共13條) 269
9.1 Formatting Data 270
9.2 Regular Expressions 278
9.3 Programmable Tools 286
9.4 Interpreters, Compilers, and Virtual Machines 289
9.5 Programs that Write Programs 296
9.6 Using Macros to Generate Code 300
9.7 Compiling on the Fly 301
Epilogue
308
Appendix: Collected Rules 311
Index 315