1. 程式人生 > >如何閱讀原始碼學習總結

如何閱讀原始碼學習總結

如何閱讀一個大型專案程式碼


對於程式設計師來說,寫程式碼永遠比讀程式碼來的舒服。但現實情況是,
程式設計師常常需要閱讀其他人員寫的程式碼,更多的時候這些程式碼可能即沒
文件也沒註釋。不過,好象有個人說過一句話,程式碼之前,了無祕密。
運用適當的策略可以讓閱讀工作變的輕鬆很多。
1. 對於常用的系統函式進行追蹤。
比如ReadFile,CreateDevice,CreateWindow,在這些函式處放幾斷點,
可以看到程式碼的呼叫過程。通過這種方式可以方便地把程式碼分為底層程式碼
和上層邏輯程式碼。
2.依據專案依賴關係進行閱讀。
專案的依賴關係同時表明了專案的複雜程度。對於大型的專案通常都會
分割成若干子專案,根據專案的依賴關係,循序漸進的方式可以讓閱讀變的簡單。
3.對於以lib形式提供的子專案。
在閱讀時,可以先把lib的整個專案做為黑盒使用。根據_declspec(dllexport)或者
以標頭檔案方式提供的呼叫介面,可以減少對於細節的閱讀時間。根據模組進行大致的劃分,
可以有效地對專案的結構有直接的感性認識。
4.識別專案中使用的設計模式。
對於大型專案來說,設計模式是必不可少的。在龐大的程式碼中識別設計模式,尋找程式碼
中使用相似手法的程式碼結構可以極大簡化需要閱讀的程式碼。
5.根據資料流程分析。
動態職責劃分。
6.修改部分程式碼,進行除錯。
修改部分常數或者饒過某些程式執行流程,或者以簡化的資料對程式進行追蹤。
========

怎麼學習閱讀大型專案的程式碼

http://blog.csdn.net/jk110333/article/details/7563718


第一章: 導論


++++++++++++




1.要養成一個習慣, 經常花時間閱讀別人編寫的高品質程式碼.


2.要有選擇地閱讀程式碼, 同時, 還要有自己的目標. 您是想學習新的模式|編碼風格|還是滿足某些需求


的方法.


3.要注意並重視程式碼中特殊的非功能性需求, 這些需求也許會導致特殊的實現風格.


4.在現有的程式碼上工作時, 請與作者和維護人員進行必要的協調, 以避免重複勞動或產生厭惡情緒.


5.請將從開放原始碼軟體中得到的益處看作是一項貸款, 儘可能地尋找各種方式來回報開放原始碼社團.


6.多數情況下, 如果您想要了解"別人會如何完成這個功能呢?", 除了閱讀程式碼以外, 沒有更好的方法.


7.在尋找bug時, 請從問題的表現形式到問題的根源來分析程式碼. 不要沿著不相關的路徑(誤入歧途).


8.我們要充分利用偵錯程式|編譯器給出的警告或輸出的符號程式碼|系統呼叫跟蹤器|資料庫結構化查詢語言


的日誌機制|包轉儲工具和Windows的訊息偵查程式, 定出的bug的位置.


9.對於那些大型且組織良好的系統, 您只需要最低限度地瞭解它的全部功能, 就能夠對它做出修改.


10.當向系統中增加新功能時, 首先的任務就是找到實現類似特性的程式碼, 將它作為待實現功能的模板.


11.從特性的功能描述到程式碼的實現, 可以按照字串訊息, 或使用關鍵詞來搜尋程式碼.


12.在移植程式碼或修改介面時, 您可以通過編譯器直接定位出問題涉及的範圍, 從而減少程式碼閱讀的工作


量.


13.進行重構時, 您從一個能夠正常工作的系統開始做起, 希望確保結束時系統能夠正常工作. 一套恰當


的測試用例(test case)可以幫助您滿足此項約束.


14.閱讀程式碼尋找重構機會時, 先從系統的構架開始, 然後逐步細化, 能夠獲得最大的效益.


15.程式碼的可重用性是一個很誘人, 但難以理解與分離, 可以試著尋找粒度更大一些的包, 甚至其他程式碼


.


16.在複查軟體系統時, 要注意, 系統是由很多部分組成的, 不僅僅只是執行語句. 還要注意分析以下內


容: 檔案和目錄結構|生成和配置過程|


使用者介面和系統的文件.


18.可以將軟體複查作為一個學習|講授|援之以手和接受幫助的機會.


++++++++++++++++++++


第二章: 基本程式設計元素


++++++++++++++++++++




19.第一次分析一個程式時, main是一個好的起始點.


20.層疊if-else if-...-else序列可以看作是由互斥選擇項組成的選擇結構.


21.有時, 要想了解程式在某一方面的功能, 執行它可能比閱讀原始碼更為恰當.


22.在分析重要的程式時, 最好首先識別出重要的組成部分.


23.瞭解區域性的命名約定, 利用它們來猜測變數和函式的功能用途.


24.當基於猜測修改程式碼時, 您應該設計能夠驗證最初假設的過程. 這個過程可能包括用編譯器進行檢查


|引入斷言|或者執行適當的測試用例.


25.理解了程式碼的某一部分, 可能幫助你理解餘下的程式碼.


26.解決困難的程式碼要從容易的部分入手.


27.要養成遇到庫元素就去閱讀相關文件的習慣; 這將會增強您閱讀和編寫程式碼的能力.


28.程式碼閱讀有許多可選擇的策略: 自底向上和自頂向下的分析|應用試探法和檢查註釋和外部文件, 應


該依據問題的需要嘗試所有這些方法.


29.for (i=0; i<n; i++)形式的迴圈執行n次; 其他任何形式都要小心.


30.涉及兩項不等測試(其中一項包括相等條件)的比較表示式可以看作是區間成員測試.


31.我們經常可以將表示式應用在樣本資料上, 藉以瞭解它的含義.


32.使用De Morgan法則簡化複雜的邏輯表示式.


33.在閱讀邏輯乘表示式時, 問題可以認為正在分析的表示式以左的表示式均為true; 在閱讀邏輯和表達


式時, 類似地, 可以認為正在分析的表示式以左的表示式均為false.


34.重新組織您控制的程式碼, 使之更為易讀.


35.將使用條件執行符? :的表示式理解為if程式碼.


36.不需要為了效率, 犧牲程式碼的易讀性.


37.高效的演算法和特殊的優化確實有可能使得程式碼更為複雜, 從而更難理解, 但這並不意味著使程式碼更為


緊湊和不易讀會提高它的效率.


38.創造性的程式碼佈局可以用來提高程式碼的易讀性.


39.我們可以使用空格|臨時變數和括號提高表示式的易讀性.


40.在閱讀您所控制的程式碼時, 要養成添加註釋的習慣.


41.我們可以用好的縮排以及對變數名稱的明智選擇, 提高編寫欠佳的程式的易讀性.


42.用diff程式分析程式的修訂歷史時, 如果這段歷史跨越了整體重新縮排, 常常可以通過指定-w選項, 


讓diff忽略空白差異, 避免由於更改了縮排層次而引入的噪音.


43.do迴圈的迴圈體至少執行一次.


44.執行算術運算時, 當b=2n-1時, 可以將a&b理解為a%(b+1).


45.將a<<n理解為a*k, k=2n.


46.將a>>n理解為a/k, k=2n.


47.每次只分析一個控制結構, 將它的內容看作是一個黑盒.


48.將每個控制結構的控制表示式看作是它所包含程式碼的斷言.


49.return, goto, break和continue語句, 還有異常, 都會影響結構化的執行流程. 由於這些語句一般


都會終止或重新開始正在進行的迴圈, 


因此要單獨推理它們的行為.


50.用複雜迴圈的變式和不變式, 對迴圈進行推理.


51.使用保持含義不變的變換重新安排程式碼, 簡化程式碼的推理工作.




+++++++++++++++++++


第三章: 高階C資料型別


+++++++++++++++++++






52.瞭解特定語言構造所服務的功能之後, 就能夠更好地理解使用它們的程式碼.


53.識別並歸類使用指標的理由.


54.在C程式中, 指標一般用來構造鏈式資料結構|動態分配的資料結構|實現引用呼叫|訪問和迭代資料元


素|傳遞陣列引數|引用函式|作為其他


值的別名|代表字串|以及直接訪問系統記憶體.


55.以引用傳遞的引數可以用來返回函式的結果, 或者避免參數複製帶來的開銷.


56.指向陣列元素地址的指標, 可以訪問位於特定索引位置的元素.


57.指向陣列元素的指標和相應的陣列索引, 作用在二者上的運算具有相同的語義.


58.使用全域性或static區域性變數的函式大多數情況都不可重入(reentrant).


59.字元指標不同於字元陣列.


60.識別和歸類應用結構或共用體的每種理由.


61.C語言中的結構將多個數據元素集合在一起, 使得它們可以作為一個整體來使用, 用來從函式中返回


多個數據元素|構造鏈式資料結構|對映


資料在硬體裝置|網路連結和儲存介質上的組織方式|實現抽象資料型別|以及以面向物件的方式程式設計.


62.共用體在C程式中主要用於優化儲存空間的利用|實現多型|以及訪問資料不同的內部表達方式.


63.一個指標, 在初始化為指向N個元素的儲存空間之後, 就可以作為N個元素的陣列來使用.


64.動態分配的內在塊可以電焊工地釋放, 或在程式結束時釋放, 或由垃圾回收器來完成回收; 在棧上分


配的記憶體塊當分配它的函式退出後釋放


.


65.C程式使用typedef宣告促進抽象, 並增強程式碼的易讀性, 從而防範可移植性問題, 並模擬C++和Java


的類宣告行為.


66.可以將typedef宣告理解成變數定義: 變數的名稱就是型別的名稱; 變數的型別就是與該名稱對應的


型別.






+++++++++++++++


第四章: C資料結構


+++++++++++++++






67.根據底層的抽象資料型別理解顯式的資料結構操作.


68.C語言中, 一般使用內建的陣列型別實現向量, 不再對底層實現進行抽象.


69.N個元素的陣列可以被序列for (i=0; i<N; i++)完全處理; 所有其他變體都應該引起警惕.


70.表示式sizeof(x)總會得到用memset或memcpy處理陣列x(不是指標)所需的正確位元組數.


71.區間一般用區間內的第一個元素和區間後的第一個元素來表示.


72.不對稱區間中元素的數目等於高位邊界與低位邊界的差.


73.當不對稱區間的高位邊界等於低位邊界時, 區間為空.


74.不對稱區間中的低位邊界代表區間的第一個元素; 高位邊界代表區間外的第一個元素.


75.結構的陣列常常表示由記錄和欄位組成的表.


76.指向結構的指標常常表示訪問底層記錄和欄位的遊標.


77.動態分配的矩陣一般儲存為指向陣列列的指標或指向元素指標的指標; 這兩種型別都可以按照二維數


組進行訪問.


78.以陣列形式儲存的動態分配矩陣, 用自定義訪問函式定位它們的元素.


79.抽象資料型別為底層實現元素的使用(或誤用)方式提供一種信心的量度.


80.陣列用從0開始的順序整數為鍵, 組織查詢表.


81.陣列經常用來對控制結構進行高效編碼, 簡化程式的邏輯.


82.通過在陣列中每個位置儲存一個數據元素和一個函式指標(指向處理資料元素的函式), 可以將程式碼與


資料關聯起來.


83.陣列可以通過儲存供程式內的抽象機(abstract machine)或虛擬機器(virtual machine)使用的資料或


程式碼, 控制程式的運作.


84.可以將表示式sizeof(x) / sizeof(x[0])理解為陣列x中元素的個數.


85.如果結構中含有指向結構自身|名為next的元素, 一般說來, 該結構定義的是單向連結串列的結點.


86.指向連結串列結點的永續性(如全域性|靜態或在堆上分配)指標常常表示連結串列的頭部.


87.包含指向自身的next和prev指標的結構可能是雙向連結串列的結點.


88.理解複雜資料結構的指標操作可以將資料元素畫為方框|指標畫為箭頭.


89.遞迴資料結構經常用遞迴演算法來處理.


90.重要的資料結構操作演算法一般用函式引數或模板引數來引數化.


91.圖的結點常常順序地儲存在陣列中, 連結到連結串列中, 或通過圖的邊連結起來.


92.圖中的邊一般不是隱式地通過指標, 就是顯式地作為獨立的結構來表示.


93.圖的邊經常儲存為動態分配的陣列或連結串列, 在這兩種情況下, 邊都錨定在圖的結點上.


94.在無向圖中, 表達資料時應該將所有的結點看作是等同的, 類似地, 進行處理任務的程式碼也不應該基


於它們的方向來區分邊.


95.在非連通圖中, 執行遍歷程式碼應該能夠接通孤立的子圖.


96.處理包含迴路的圖時, 遍歷程式碼應該避免在處理圖的迴路進入迴圈.


97.複雜的圖結構中, 可能隱藏著其他型別的獨立結構.






+++++++++++++++++


第五章: 高階控制流程


+++++++++++++++++






98.採用遞迴定義的演算法和資料結構經常用遞迴的函式定義來實現.


99.推理遞迴函式時, 要從基準落伍測試開始, 並認證每次遞迴呼叫如何逐漸接近非遞迴基準範例程式碼.


100.簡單的語言常常使用一系列遵循該語言語法結構的函式進行語法分析.


101.推理互遞迴函式時, 要基於底層概念的遞迴定義.


102.尾遞迴呼叫等同於一個回到函式開始處的迴圈.


103.將throws子句從方法的定義中移除, 然後執行Java編譯器對類的原始碼進行編譯, 就可以容易地找


到那些可能隱式地生成異常的方法.


104.在多處理器計算機上執行的程式碼常常圍繞程序或執行緒進行組織.


105.工作群並行模型用於在多個處理器間分配工作, 或者建立一個任務池, 然後將大量需要處理標準化


的工作進行分配.


106.基於執行緒的管理者/工人並行模型一般將耗時的或阻塞的操作分配給工人子任務, 從而維護中心任務


的響應性.


107.基於程序的管理者/工人並行模型一般用來重用現有的程式, 或用定義良好的介面組織和分離粗粒度


的系統模組.


108.基於流水線的並行處理中, 每個任務都接收到一些輸入, 對它們進行一些處理, 並將生成的輸出傳


遞給下一個任務, 進行不同的處理.


109.競爭條件很難捉摸, 相關的程式碼常常會將競爭條件擴散到多個函式或模組; 因而, 很難隔離由於競


爭條件導致的問題.


110.對於出現在訊號處理器中的資料結構操作程式碼和庫呼叫要保持高度警惕.


111.在閱讀包含巨集的程式碼時, 要注意, 巨集既非函式, 也非語句.


112.do…while(0)塊中的巨集等同於控制塊中的語句.


113.巨集可以訪問在它的使用點可見的所有區域性變數.


114.巨集呼叫可改變引數的值


115.基於巨集的標記拼接能夠建立新的標記符.




+++++++++++++++++


第六章: 應對大型專案


+++++++++++++++++






116.我們可以通過瀏覽專案的原始碼樹—包含專案原始碼的層次目錄結構, 來分析一個專案的組織方式. 


原始碼樹常常能夠反映出專案在構架和軟體過程上的結構.


117.應用程式的原始碼樹經常是該應用程式的部署結構的映象.


118.不要被龐大的原始碼集合嚇倒; 它們一般比小型的專門專案組織得更出色.


119.當您首次接觸一個大型專案時, 要花一些時間來熟悉專案的目錄樹結構.


120.專案的原始碼遠不只是編譯後可以獲得可執行程式的計算機語言指令; 一個專案的原始碼樹一般還包


括規格說明|終端使用者和開發人員文件|測試指令碼|多媒體資源|編譯工具|例子|本地化檔案|修訂歷史|安


裝過程和許可資訊.


121.大型專案的編譯過程一般宣告性地藉助依賴關係來說明. 依賴關係由工具程式, 如make及其派生程


序, 轉換成具體的編譯行動.


122.大型專案中, 製作檔案常常由配置步驟動態地生成; 在分析製作檔案之前, 需要先執行專案特定的


配置.


123.檢查大型編譯過程的各個步驟時, 可以使用make程式的-n開關進行預演.


124.修訂控制系統提供從儲存庫中獲取原始碼最新版本的方式.


125.可以使用相關的命令, 顯示可執行檔案中的修訂標識關鍵字, 從而將可執行檔案與它的原始碼匹配


起來.


126.使用修訂日誌中出現的bug跟蹤系統內的編號, 可以在bug跟蹤系統的資料庫中找到有關的問題的說


明.


127.可以使用修訂控制系統的版本儲存庫, 找出特定的變更是如何實現的.


128.定製編譯工具用在軟體開發過程的許多方面, 包括配置|編譯過程管理|程式碼的生成|測試和文件編制


.


129.程式的除錯輸出可以幫助我們理解程式控制流程和資料元素的關鍵部分.


130.跟蹤語句所在的地點一般也是演算法執行的重要部分.


131.可以用斷言來檢驗演算法運作的步驟|函式接收的引數|程式的控制流程|底層硬體的屬性和測試用例的


結果.


132.可以使用對演算法進行檢驗的斷言來證實您對演算法運作的理解, 或將它作為推理的起點.


133.對函式引數和結果的斷言經常記錄了函式的前置條件和後置條件.


134.我們可以將測試整個函式的斷言作為每個給定函式的規格說明.


135.測試用例可以部分地代替函式規格說明.


136.可以使用測試用例的輸入資料對原始碼序列進行預演.






+++++++++++++++++++


第七章: 編碼規範和約定


+++++++++++++++++++






137.瞭解了給定程式碼庫所遵循的檔案組織方式後, 就能更有效率地瀏覽它的原始碼.


138.閱讀程式碼時, 首先要確保您的編輯器或優美列印程式的tab設定, 與程式碼遵循的風格規範一致.


139.可以使用程式碼塊的縮排, 快速地掌握程式碼的總體結構.


140.對編排不一致的程式碼, 應該立即給予足夠的警惕.


141.分析程式碼時, 對標記為XXX, FIXME和TODO的程式碼序列要格外注意: 錯誤可能就潛伏在其中.


142.常量使用大寫字母命名, 單詞用下劃線分隔.


143.在遵循Java編碼規範的程式中, 包名(package name)總是從一個頂級的域名開始(例如, org, com), 


類名和介面名由大寫字母開始, 方法和變數名由小寫字母開始.


144.使用者介面控制元件名稱之前的匈牙利記法的字首型別標記可以幫助我們確定它的作用.


145.不同的程式設計規範對可移植構造的構成有不同的主張.


146.在審查程式碼的可移植性, 或以某種給定的編碼規範作為指南時, 要注意瞭解規範對可移植性需求的


界定與限制.


147.如果GUI功能都使用相應的程式設計結構來實現, 則通過程式碼審查可以輕易地驗證給定使用者介面的規格說


明是否被正確地採用.


148.瞭解專案編譯過程的組織方式與自動化方式之後, 我們就能夠快速地閱讀與理解對應的編譯規則.


149.當檢查系統的釋出過程時, 常常可以將相應發行格式的需求作為基準.




++++++++++++


第八章: 文件


++++++++++++






150.閱讀程式碼時, 應該儘可能地利用任何能夠得到的文件.


151.閱讀一小時程式碼所得到的資訊只不過相當於閱讀一分鐘文件.


152.使用系統的規格說明文件, 瞭解所閱讀程式碼的執行環境.


153.軟體需求規格說明是閱讀和評估程式碼的基準.


154.可以將系統的設計規格說明作為認知程式碼結構的路線圖, 閱讀具體程式碼的指引.


155.測試規格說明文件為我們提供可以用來對程式碼進行預演的資料.


156.在接觸一個未知系統時, 功能性的描述和使用者指南可以提供重要的背景資訊,從而更好地理解閱讀的


程式碼所處的上下文.


157.從使用者參考手冊中, 我們可以快速地獲取, 應用程式在外觀與邏輯上的背景知識, 從管理員手冊中


可以得知程式碼的介面|檔案格式和錯誤訊息的詳細資訊.


158.利用文件可以快捷地獲取系統的概況, 瞭解提供特定特性的程式碼.


159.文件經常能夠反映和提示出系統的底層結構.


160.文件有助於理解複雜的演算法和資料結構.


161.演算法的文字描述能夠使不透明(晦澀, 難以理解)的程式碼變得可以理解.


162.文件常常能夠闡明原始碼中識別符號的含義.


163.文件能夠提供非功能性需求背後的理論基礎.


164.文件還會說明內部程式設計介面.


165.由於文件很少像實際的程式程式碼那樣進行測試, 並受人關注, 所以它常常可能存在錯誤|不完整或過


時.


166.文件也提供測試用例, 以及實際應用的例子.


167.文件常常還會包括已知的實現問題或bug.


168.環境中已知的缺點一般都會記錄在原始碼中.


169.文件的變更能夠標出那些故障點.


170.對同一段原始碼重複或互相沖突的更改, 常常表示存在根本性的設計缺陷, 從而使得維護人員需要


用一系列的修補程式來修復.


171.相似的修復應用到原始碼的不同部分, 常常表示一種易犯的錯誤或疏忽, 它們同樣可能會在其他地


方存在.


172.文件常常會提供不恰當的資訊, 誤導我們對原始碼的理解.


173.要警惕那些未歸檔的特性: 將每個例項歸類為合理|疏忽或有害, 相應地決定是否應該修復程式碼或文


檔.


174.有時, 文件在描述系統時, 並非按照已完成的實現, 而是系統應該的樣子或將來的實現.


175.在原始碼文件中, 單詞gork的意思一般是指”理解”.


176.如果未知的或特殊用法的單詞阻礙了對程式碼的理解, 可以試著在文件的術語表(如果存在的話)|New 


Hacker’s Dictionary[Ray96]|或在


Web搜尋引擎中查詢它們.


177.總是要以批判的態度來看待文件, 注意非傳統的來源, 比如註釋|標準|出版物|測試用例|郵件列表|


新聞組|修訂日誌|問題跟蹤資料庫|營銷材料|原始碼本身.


178.總是要以批判的態度來看待文件; 由於文件永遠不會執行, 對文件的測試和正式複查也很少達到對


程式碼的同樣水平, 所以文件常常會誤導讀者, 或者完全錯誤.


179.對於那些有缺陷的程式碼, 我們可以從中推斷出它的真實意圖.


180.在閱讀大型系統的文件時, 首先要熟悉文件的總體結構和約定.


181.在對付體積龐大的文件時, 可以使用工具, 或將文字輸出到高品質輸出裝置上, 比如鐳射印表機, 


來提高閱讀的效率.






++++++++++++++


第九章: 系統構架


++++++++++++++






182.一個系統可以(在重大的系統中也確實如此)同時出多種不同的構架型別. 以不同的方式檢查同一系


統|分析系統的不同部分|或使用不同級別的分解, 都有可能發現不同的構架型別.


183.協同式的應用程式, 或者需要協同訪問共享資訊或資源的半自治程序, 一般會採用集中式儲存庫構


架.


184.黑板系統使用集中式的儲存庫, 儲存非結構化的鍵/值對, 作為大量不同程式碼元件之間的通訊集線器


.


185.當處理過程可以建模|設計和實現成一系列的資料變換時, 常常會使用資料流(或管道—過濾器)構架


.


186.在批量進行自動資料處理的環境中, 經常會採用資料流構架, 在對資料工具提供大量支援的平臺上


尤其如此.


187.資料流構架的一個明顯徵兆是: 程式中使用臨時檔案或流水線(pipeline)在不同程序間進行通訊.


188.使用圖示來建模面向物件構架中類的關係.


189.可以將原始碼輸入到建模工具中, 逆向推匯出系統的構架.


190.擁有大量同級子系統的系統, 常常按照分層構架進行組織.


191.分層構架一般通過堆疊擁有標準化介面的軟體元件來實現.


192.系統中每個層可以將下面的層看作抽象實體, 並且(只要該層滿足它的需求說明)不關心上面的層如


何使用它.


193.層的介面既可以是支援特定概念的互補函式族, 也可以是一系列支援同一抽象介面不同底層實現的


可互換函式.


194.用C語言實現的系統, 常常用函式指標的陣列, 表達層介面的多路複用操作.


195.用面向物件的語言實現的系統, 使用虛方法呼叫直接表達對層介面的多嘴複用操作.


196.系統可以使用不同的|獨特的層次分解模型跨各種座標軸進行組織.


197.使用程式切片技術, 可以將程式中的資料和控制之間依賴關係集中到一起.


198.在併發系統中, 一個單獨的系統元件起到集中式管理器的作用, 負責啟動|停止和協調其他系統程序


和任務的執行.


199.許多現實的系統都會博採眾家之長. 當處理此類系統時, 不要徒勞地尋找無所不包的構架圖; 應該


將不同構架風格作為獨立但相關的實體來進行定位|識別並瞭解.


200.狀態變遷圖常常有助於理清狀態機的動作.


201.在處理大量的程式碼時, 瞭解將程式碼分解成單獨單元的機制極為重要.


202.大多數情況下, 模組的物理邊界是單個檔案|組織到一個目錄中的多個檔案或擁有統一字首的檔案的


集合.


203.C中的模組, 由提供模組公開介面的標頭檔案和提供對應實現的原始檔組成.


204.物件的建構函式經常用來分配與物件相關的資源, 並初始化物件的狀態. 函式一般用來釋放物件在


生命期中佔用的資源.


205.物件方法經常使用類欄位來儲存控制所有方法運作的資料(比如查詢表或字典)或維護類運作的狀態


資訊(例如, 賦給每個物件一個識別符號的計數器).


206.在設計良好的類中, 所有的欄位都應在宣告為private, 並用公開的訪問方法提供對它們的訪問.


207.在遇到friend宣告時, 要停下來分析一下, 看看繞過類封裝在設計上的理由.


208.可以有節制地用運算子增強特定類的可用性, 但用運算子過載, 將類實現為擁有內建算術型別相關


的全部功能的類實體, 是不恰當的.


209.泛型實現不是在編譯期間通過巨集替換或語言所支援的功能(比如C++模板和Ada的泛型包)來實現, 就


是在執行期間通過使用資料元素的指標和函式的指標|或物件的多型性實現.


210.抽象資料型別經常用來封裝常用的資料組織方案(比如樹|列表或棧), 或者對使用者隱藏資料型別的實


現細節.


211.使用庫的目的多種多樣: 重用原始碼或目的碼, 組織模組集合, 組織和優化編譯過程, 或是用來


實現應用程式各種特性的按需載入.


212.大型的|分散式的系統經常實現為許多互相協作的程序.


213.對於基於文字的資料儲存庫, 可以通過瀏覽儲存在其中的資料, 破譯出它的結構.


214.可以通過查詢資料字典中的表, 或使用資料庫專有的SQL命令, 比如show table, 來分析關係型資料


庫的模式.


215.識別出重用的構架元素後, 可以查詢其最初的描述, 瞭解正確地使用這種構架的方式, 以及可能出


現的誤用.


216.要詳細分析建立在某種框架之上的應用程式, 行動的最佳路線就是從研究框架自身開始.


217.在閱讀嚮導生成的程式碼時, 不要期望太高, 否則您會感到失望.


218.學習幾個基本的設計模式之後, 您會發現, 您檢視程式碼構架的方式會發生改變: 您的視野和詞彙將


會擴充套件到能夠識別和描述許多通用的形式.


219.頻繁使用的一些模式, 但並不顯式地指出它們的名稱, 這是由於構架性設計的重用經常先於模式的


形成.


220.請試著按照底層模式來理解構架, 即使程式碼中並沒有明確地提及模式.


221.大多數直譯器都遵循類似的處理構架, 圍繞一個狀態機進行構建, 狀態機的操作依賴於直譯器的當


前狀態|程式指令和程式狀態.


222.多數情況下, 參考構架只是為應用程式域指定一種概念性的結構, 具體的實現並非必須遵照這種結


構.




+++++++++++++++++


第十章: 程式碼閱讀工具


+++++++++++++++++






223.詞彙工具可以高效地在一個大程式碼檔案中或者跨多個檔案查詢某種模式.


224.使用程式編輯器和正則表示式查詢命令, 瀏覽龐大的原始碼檔案.


225.以只讀方式瀏覽原始碼檔案.


226.使用正則表示式 ^function name 可以找出函式的定義.


227.使用正則表示式的字元類, 可以查詢名稱遵循特定模式的變數.


228.使用正則表示式的否定字元類, 可以避免非積極匹配.


229.使用正則表示式 symbol-1. *symbol-2, 可以查找出現在同一行的符號.


230.使用編輯器的 tags 功能, 可以快速地找出實體的定義.


231.可以用特定的 tag 建立工具, 增加編輯器的瀏覽功能.


232.使用編輯器的大綱檢視, 可以獲得原始碼結構的鳥瞰圖.


233.使用您的編輯器來檢測原始碼中圓括號|方括號和花括號的匹配.


234.使用 grep 跨多個檔案查詢程式碼模式.


235.使用 grep 定位符號的宣告|定義和應用.


236.當您不能精確地表述要查詢的內容時, 請使用關鍵單詞的詞幹對程式的原始碼進行查詢.


237.用 grep 過濾其他工具生成的輸出, 分離出您要查詢的項.


238.將 grep 的輸出輸送到其他工具, 使複雜處理任務自動化.


239.通過對 grep 的輸出進行流編輯, 重用程式碼查詢的結果.


240.通過選取與噪音模式不匹配的輸出行(grep-v), 過濾虛假的 grep 輸出.


241.使用 fgrep 在原始碼中查詢字串列表.


242.查詢註釋, 或識別符號大小寫不敏感的語言編寫的程式碼時, 要使用大小寫不敏感的模式匹配(grep -


i).


243.使用 grep –n 命令列開關, 可以建立與給定正則表示式匹配的檔案和行號的檢查表.


244.可以使用 diff 比較檔案或程式不同版本之間的差別.


245.在執行 diff 命令時, 可以使用 diff –b, 使檔案比較演算法忽略結尾的空格, 用 –w 忽略所有空


白區域的差異, 用 –i 使檔案比較對大小寫不敏感.


246.不要對建立自己的程式碼閱讀工具心存畏懼.


247.在構建自己的程式碼閱讀工具時: 要充分利用現代快速原型語言所提供的能力; 從簡單開始, 根據需


要逐漸改進; 使用利用程式碼詞彙結構的各種試探法; 要允許一些輸出噪音或寂靜(無關輸出或缺失輸出); 


使用其他工具對輸入進行預處理, 或者對輸出進行後期處理.


248.要使編譯器成為您的: 指定恰當級別的編譯器警告, 並小心地評估生成的結果.


249.使用C前處理器理清那些濫用前處理器特性的程式.


250.要徹底地瞭解編譯器如何處理特定的程式碼塊, 需要檢視生成的符號(彙編)程式碼.


251.通過分析相應目標檔案中的符號, 可以清晰地瞭解原始檔的輸入和輸出.


252.使用原始碼瀏覽器瀏覽大型的程式碼集合以及物件型別.


253.要抵制住按照您的編碼規範對外部程式碼進行美化的誘惑; 不必要的編排更改會建立不同的程式碼, 並


妨礙工作的組織.


254.優美列印程式和編輯器語法著色可以使得程式的原始碼為易讀.


255.cdecl 程式可以將難以理解的C和C++型別宣告轉換成純英語(反之亦然).


256.實際執行程式, 往往可以更深刻地理解程式的動作.


257.系統呼叫|事件和資料包跟蹤程式可以增進對程式動作的理解.


258.執行剖析器可以找出需要著重優化的程式碼, 驗證輸入資料的覆蓋性, 以及分析演算法的動作.


259.通過檢查從未執行的程式碼行, 可以找出測試覆蓋的弱點, 並據此修正測試資料.


260.要探究程式動態動作時的每個細節, 需要在偵錯程式中運作它.


261.將您覺得難以理解的程式碼列印到紙上.


262.可以繪製圖示來描繪程式碼的動作.


263.可以試著向別人介紹您在閱讀的程式碼, 這樣做一般會增進您對程式碼的理解.


264.理解複雜的演算法或巧妙的資料結構, 要選擇一個安靜的環境, 然後聚精會神地考慮, 不要藉助於任


何計算機化或自動化的幫助.






+++++++++++++++++++++


第十一章: 一個完整的例子


+++++++++++++++++++++






265.模仿軟體的功能時, 要依照相似實體的線路(類|函式|模組). 在相似的現有實體中, 為簡化對源代


碼庫的文字查詢, 應選取比較罕見的名稱.


266.自動生成的檔案常常會在檔案的開關有一段註釋, 說明這種情況.


267.如果試圖精確地分析程式碼, 一般會陷入數量眾多的類|檔案和模組中, 這些內容會很快將我們淹沒; 


因此, 我們必須將需要理解的程式碼限定在絕對必需的範圍之內.


268.採用一種廣度優先查詢策略, 從多方攻克程式碼閱讀中存在的問題, 進到找出克服它們的方法為止.
========

大牛們是怎麼閱讀 Android 系統原始碼的

最近想去深入學習下底層的東西。


由於工作需要大量修改framework程式碼, 在AOSP(Android Open Source Project)原始碼上花費了不少功夫, 


Application端和Services端都看和改了不少.
如果只是想看看一些常用類的實現, 在Android包管理器裡把原始碼下載下來, 隨便一個IDE配好Source 


Code的path看就行. 
但如果想深入的瞭解Android系統, 那麼可以看下我的一些簡單的總結. 


知識
Java
Java是AOSP的主要語言之一. 沒得說, 必需熟練掌握.
熟練的Android App開發
Linux
Android基於Linux的, 並且AOSP的推薦編譯環境是Ubuntu 12.04. 所以熟練的使用並瞭解Linux這個系統


是必不可少的. 如果你想了解偏底層的程式碼, 那麼必需瞭解基本的Linux環境下的程式開發. 如果再深入


到驅動層, 那麼Kernel相關的知識也要具備.
Make
AOSP使用Make系統進行編譯. 瞭解基本的Makefile編寫會讓你更清晰瞭解AOSP這個龐大的專案是如何構


建起來的.
Git
AOSP使用git+repo進行原始碼管理. 這應該是程式設計師必備技能吧.
C++
Android系統的一些效能敏感模組及第三方庫是用C++實現的, 比如: Input系統, Chromium專案(WebView


的底層實現).


硬體
流暢的國際網路
AOSP程式碼下載需要你擁有一個流暢的國際網路. 如果在下載程式碼這一步就失去耐心的話, 那你肯定沒有


耐心去看那亂糟糟的AOSP程式碼. 另外, 好程式設計師應該都會需要一個流暢的Google.
一臺執行Ubuntu 12.04的PC.
如果只是閱讀原始碼而不做太多修改的話, 其實不需要太高的配置.
一臺Nexus裝置
AOSP專案預設只支援Nexus系列裝置. 沒有也沒關係, 你依然可以讀程式碼. 但如果你想在大牛之路走的更


遠, 還是改改程式碼, 然後刷機除錯看看吧.
高品質USB線
要刷機時線壞了, 沒有更窩心的事兒了.
軟體
Ubuntu 12.04
官方推薦, 沒得選.
Oracle Java 1.6
注意不要用OpenJDK. 這是個坑, 官方文件雖然有寫, 但還是單獨提一下.
安裝:
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java6-installer
sudo apt-get install oracle-java6-set-default


Eclipse
估計會有不少人吐槽, 為什麼要用這個老古董. 其實原因很簡單, 合適. 剛開始搞AOSP時, 為了找到效


率最優的工具, 我嘗試過Eclipse, IntelliJ IDEA, Vim+Ctags, Sublime Text+Ctags. 最終結果還是


Eclipse. 主要優點有:
有語法分析 (快速準確的類, 方法跳轉).
支援C++ (IntelliJ的C++支援做的太慢了).
嵌入了DDMS, View Hierarchy等除錯工具.
為了提高效率, 花5分鐘背下常用快捷鍵非常非常值得.
調整好你的classpath, 不要匯入無用的程式碼. 因為AOSP專案程式碼實在是太多了. 當你還不需要看C++代


碼時, 不要為專案新增C++支援, 建索引過程會讓你崩潰.
Intellij IDEA
開發App必備. 當你要除錯系統的某個功能是, 常常需要迅速寫出一個除錯用App, 這個時候老舊的


Eclipse就不好用了. Itellij IDEA的xml自動補全非常給力.
巨人的肩膀
AOSP專案官方: https://source.android.com/source/index.html
這個一定要先讀. 專案介紹, 程式碼下載, 環境搭建, 刷機方法, Eclipse配置都在這裡. 這是一切的基礎


.
Android官方Training: https://developer.android.com/training/index.html
這個其實是給App開發者看的. 但是裡面也有不少關於系統機制的介紹, 值得細讀.
老羅的Android之旅: http://blog.csdn.net/luoshengyang
此老羅非彼老羅. 羅昇陽老師的部落格非常有營養, 基本可以作為指引你開始閱讀AOSP原始碼的教程. 你可


以按照部落格的時間順序一篇篇挑需要的看.但這個系列的部落格有些問題:
早期的部落格是基於舊版本的Android;
大量的程式碼流程追蹤. 讀文章時你一定要清楚你在看的東西在整個系統處於什麼樣的位置.
Innost的專欄: http://blog.csdn.net/innost
鄧凡平老師也是為Android大牛, 部落格同樣很有營養. 但是不像羅昇陽老師的那麼系統. 更多的是一些技


術點的深入探討.
Android Issues: http://code.google.com/p/android/issues/list
Android官方Issue列表. 我在開發過程中發現過一些奇怪的bug, 最後發現這裡基本都有記錄. 當然你可


以提一些新的, 有沒有人改就是另外一回事了.
Google: https://www.google.com
一定要能流暢的使用這個工具. 大量的相關知識是沒有人系統的總結的, 你需要自己搞定.
其它
程式碼組織
AOSP的編譯單元不是和git專案一一對應的, 而是和Android.mk檔案一一對應的. 善用mmm命令進行模組


編譯將節省你大量的時間.
Binder
這是Android最基礎的程序間通訊. 在Application和System services之間大量使用. 你不僅要知道AIDL


如何使用, 也要知道如何手寫Binder介面. 這對你理解Android的Application和System services如何交


互有非常重要的作用. Binder如何實現的倒不必著急看.
HAL
除非你對硬體特別感興趣或者想去方案公司上班, 否則別花太多時間在這一層.
CyanogenMod
這是一個基於AOSP的第三方Rom. 從這個專案的wiki裡你能學到很多AOSP官方沒有告訴你的東西. 比如如


何支援Nexus以外的裝置.
DIA
這是一個Linux下畫UML的工具, 能夠幫你梳理看過的程式碼.
XDA
http://www.xda-developers.com/
這裡有最新資訊和最有趣的論壇.
想到了再補充.


在Android系統原始碼上摸索4年,說說我的看法:
顯然Eclipse不是閱讀Android原始碼的好工具,不流暢,搜尋低效,繼承性關係/呼叫關係都無法有效檢視


。推薦Source Insight,在這個工具幫助下,你才可以駕馭巨大數量的Android 原始碼,你可以從容在


Java,C++,C程式碼間遨遊,你可以很快找到你需要的繼承和呼叫關係。
順便,現在東家是Linux+Samba+Windows的工作模式,Linux+Samba用於程式碼的同步/編譯/管理,Windows


做程式碼編輯。
你需要先理解下這個圖:Application層就是一個個應用程式,很好理解。Framework提供一個java的運


行環境以及對功能實現的封裝,簡單點說,你家裝修總要留很多水電之類的介面吧!Runtime/ART是一個


java虛擬機器,因為Android上層不是java嗎,需要再編譯一次成為低階一點的語言識別。從Libraries那


些名字也可以看出來,這裡有很多高階大氣庫,它是功能實現區,多媒體編解碼,瀏覽器渲染啊,資料


庫實現啦,很多很多。Kernel部分負責陪硬體大哥玩,你那些功能實現的區域最終都要調硬體吧,


Kernel這傢伙已經和硬體很熟了,你就直接通過它來和冷冰冰硬體大哥打交道吧!




好了,上面這些內容很好理解對不對,現在的問題是:當你拿到一份幾G的原始碼,該從哪裡開始呢?經過


上面的前言的洗禮,你應該能夠很好理解下面這部分了


1.巨集觀上看,Android原始碼分為功能實現上的縱向,和功能拓展上的橫向。在閱讀原始碼時需要把握好著兩


個思路。
譬如你需要研究音訊系統的實現原理,縱向:你需要從一個音樂的開始播放追蹤,一路下來,你發現解


碼庫的呼叫,共享記憶體的建立和使用,路由的切換,音訊輸入裝置的開啟,音訊流的開始。
譬如你要看音訊系統包括哪些內容,橫向:通過Framework的介面,你會發現,音訊系統主要包括:放音


,錄音,路由切換,音效處理等。


2.Android的功能模組絕大部分是C/S架構
你心裡一定需要有這個層級關係,你需要思路清晰地找到Server的位置,它才是你需要攻破的城,上面


的libraries是不是很親切的樣子?看完它長成啥樣後,然後你才能發現HAL和Kernel一層層地剝離。
很多研究原始碼的同學兜兜轉轉,始終在JAVA層上,這是不科學的,要知道libraries才是它的精髓啊。
3.Android的底層是Linux Kernel。
在理解1,2後,還是需要對Kernel部分有個簡單的理解,起碼你要熟悉kernel的基礎協議吧!你要能看懂


電路圖吧!你要熟悉裝置的開啟和關閉吧!你要熟悉調暫存器了吧!這方面的書太多了,我建議根據實


例去閱讀,它並不複雜,不需要一本本厚書來鋪墊。
在libraries和kernel間,可能還會有個HAL的東東,其實它是對kernel層的封裝,方便各個硬體的介面


統一。這樣,如果我換個硬體,不用跑了長得很複雜的libraries裡面改了,kernel除錯好了後,改改


HAL就好了。


好了,你現在是不是躍躍欲試準備去找個突破口準備進攻了,但是好像每個寶庫的入口都挺難找了
我大概在三個月前閱讀完Android UI系統的原始碼,這是Android最複雜的部分,我要簡單說下過程。


我需要先找寶庫入口,我要研究UI,首先要找什麼和UI有親戚關係吧!
View大神跳出來了,沿著它往下找找看,發現它在貼圖在畫各種形狀,但是它在哪裡畫呢,馬良也要紙


吧?
很明顯它就是某個寶藏,但是世人只是向我們描述了它有多美,卻無人知在哪裡?我們需要找一張地圖


羅。
開發Android的同學逃不掉Activity吧!它有個setcontentview的方法,從這個名字看好像它是把view和


activity結合的地方。趕緊看它的實現和被呼叫。,然後我們就發現了Window,ViewRoot和


WindowManager的身影,沿著WM和WMS我們就驚喜會發現了Surface,以及draw的函式,它居然在一個


DeCorView上畫東西哈。藉助Source Insight, UI Java層的橫向靜態圖呼之欲出了。


完成這個靜態UML,我覺得我可以開始功能實現上追蹤了,這部分主要是C++的程式碼(這也是我堅定勸阻


的放棄Eclipse的原因),我沿著draw函式,看到了各個層級的關係,SurfaceSession的控制和事務處理


,SharedBuffer讀寫控制,彪悍的SurfaceFlinger主宰一切,OpenGL ES的神筆馬良。FrameBuffer和


FrameBufferDevice的影象輸出,LCD裝置開啟後,開始接收FBD發過來的一幀幀影象,神奇吧。


好吧,就這樣,再往底層我愛莫能助了!


工具:Android Studio
檢視原始碼方法: http://androidperformance.com/2015/01/16/view-android-source-code-with-


androidstudio.html
看那一部分:
Framework/base
Package/apps
art
external


作業系統:推薦Linux,可以隨時編譯Android原始碼
測試機:推薦Nexus系列手機,編譯原始碼後push進去可以隨時驗證。


Android原始碼兩個部分看得最多,一個是packages,就是各個系統應用的實現,另外就是framework,框


架層的實現。具體看什麼就看你想了解什麼。


工具eclipse也很好,build一下生成class path,各種轉跳非常方便,不需要grep了。


vim+grep. 讀任何程式碼都是一樣的. android 並沒什麼特殊的


我覺得vim+tags已經很爽了,當然要是source insight出個Mac版本就更好了。


最近想去深入學習下底層的東西。看的哪一部分?
程式碼裡面的部分,那就學學Linux Kernel,Bootloader,再底層的需要學些硬體驅動,一步一步來。


有沒有好的檢視工具?
Windows 下推薦SoureInsight,建個工程把AOSP 所有程式碼丟進去,幾個月不用關掉,看到感興趣的地方


不停的往下追就好。當初就在這上面直接改程式碼,Ubuntu 開個視窗編譯搞定,其實是懶得開IDE(逃


因為工作原因,接觸 Android 原始碼並且折騰的很早,也因為工作原因,無法有效的利用各種 IDE, 所以


一直是用 VIM + grep 的方式。效率可能比較低下,但是讀原始碼這種東西就是貴在堅持學習,看的時間


長了,慢慢哪些程式碼在什麼地方都大概能有印象,所以讀和找起來就很方便。蠻羨慕會用 taglist 的,


只是一直不大習慣使用。
再有比較關鍵的一點是多找一些身邊喜歡學習的朋友交流,每個人看的可能都不一樣,很多時候突破口


就在抽菸聊天的時間討論出來的。


零、準備工作:
開發環境:建議在ubuntu(32/64位均可)下進行開發。
開發板:推薦cubieboard、pcduino
(資料開放,連相應的android原始碼以及硬體配置檔案都有提供。
不推薦所謂的開源硬體Raspberry-Pi,畢竟Raspberry-Pi並不是真正的開源硬體。)
其他:串列埠線


強烈不推薦在windows環境下搞Android底層開發!!!
一個及格的Android工程師,就應該熟練在Linux環境下進行開發工作。
如果你不會“優雅”地使用Linux,不得不在windows下編輯程式碼,
懇請你記得設定編碼utf-8!!!!!!!!!!
(怨念:每次編譯韌體看見亂碼警告就各種強迫症啊摔ヽ(≧Д≦)ノ!儘管大多情況下不影響編譯結果


。)


一、編譯器的選擇:
閱讀/編譯程式碼:eclipse (Java)、vim+ctags+cscope(C/C++)
搜尋程式碼:shell
例如命令1:grep "Telephoney" -rn ./*
例如命令2:find -name Telephoney*
等等等


不會用eclipse,請不要說他不好用!
eclipse是閱讀framework程式碼以及系統應用的居家旅行殺人必備神器。
正確使用eclipse閱讀Android原始碼:
1.複製eclipse的classpath到Android原始碼根目錄
cp ~/android/development/ide/eclipse/.classpath ~/android
2.修改eclipse快取設定
把eclipse.ini檔案的3個值改為下面的值(不要盲目參考,需要根據自己機器情況來定):
-Xms128m
-Xmx768m
-XX:MaxPermSize=512m
(mac路徑:eclipse/Eclipse.app/Contents/MacOS/eclipse.ini)
3.匯入eclipse程式碼風格
把android-formatting.xml和android.importorder匯入Eclipse
~/android/development/ide/eclipse/android-formatting.xml
~/android/development/ide/eclipse/android.importorder
4.匯入Android原始碼
新建Java Project(不是Android project),選擇從已存在的工程匯入,定位到Android原始碼的目錄進


行匯入即可。
PS:eclipse只是閱讀/編輯程式碼的工具,編譯原始碼還是需要通過make命令在終端編譯的。 


二、知識儲備:
程式語言什麼的沒什麼好說。
著重提一個:設計模式
由於Android原始碼用到各種各樣的設計模式,如果不會設計模式,將會大大降低你的閱讀理解速度。


三、網站資料:
http://source.android.com/devices
android官方文件,很詳細描述各模組的設計思路。
理解這個連結的內容,看個十遍八遍,一邊看一邊分析程式碼。
PS:由於比較笨(-’๏_๏’-),所以我當年是一邊看一邊翻譯出來,大家也可以參考我這種方法,容易加


深理解、印象


四、書刊資料:
鄧凡平大神的《深入理解Android》系列
《深入理解Android:卷I/卷​II》 [Kindle電子書] ~ 鄧凡平
連結:http://www.amazon.cn/dp/B00K6Y5OEM
作者Blog:http://blog.csdn.net/Innost/


五、學習方法:
要一下子把所有模仿都理解透,是件比較困難的事情。
可以分模組學習:
Telephoney
Audio & media
webkit & Browser
Wi-Fi & wpa supplicant
Dalvik
Display & Surface flinger
Camera
等等等




分享自己總結的一些閱讀原始碼的方法,需要注意的幾個點可以注意下
做什麼事情都要知道從那裡開始,讀程式也不例外。在c語言裡,首先要找到main()函式,然後逐層去閱


讀,其他的程式無論是vb、delphi都要首先找到程式頭,否則你是很難分析清楚程式的層次關係。
分層次閱讀
  在閱讀程式碼的時候不要一頭就紮下去,這樣往往容易只見樹木不見森林,閱讀程式碼比較好的方法有


一點象二叉樹的廣度優先的遍歷。在程式主體一般會比較簡 單,呼叫的函式會比較少,根據函式的名字


以及層次關係一般可以確定每一個函式的大致用途,將你的理解作為註解寫在這些函式的邊上。當然很


難一次就將全部注 解都寫正確,有時候甚至可能是你猜測的結果,不過沒有關係這些註解在閱讀過程是


不斷修正的,直到你全部理解了程式碼為止。一般來說採用逐層閱讀的方法可以是 你係統的理解保持在一


個正確的方向上。避免一下子扎入到細節的問題上。在分層次閱讀的時候要注意一個問題,就是將系統


的函式和開發人員編寫程式碼區分開。在 c, c++,java ,delphi中都有自己的系統函式,不要去閱讀這些


系統函式,除非你要學習他們的程式設計方法,否則只會浪費你的時間。將系統函式表示出來,註明它們的


作用 即可,區分系統函式和自編函式有幾個方法,一個是系統函式的程式設計風格一般會比較好,而自編的


函式的程式設計風格一般比較會比較差。從變數名、行之間的縮排、注 解等方面一般可以分辨出來,另外一


個是象ms c6++會在你程式設計的時候給你生成一大堆檔案出來,其中有很多檔案是你用不到了,可以根據文


件名來區分一下時候是系統函式,最後如果你實在確定不了,那就 用開發系統的幫助系統去查一下函式


名,對一下引數等來確定即可。
重複閱讀
  一次就可以將所有的程式碼都閱讀明白的人是沒有的。至少我還沒有遇到過。反覆的去閱讀同一段代


碼有助於得程式碼的理解。一般來說,在第一次閱讀程式碼的時候 你可以跳過很多一時不明白的程式碼段,只


寫一些簡單的註解,在以後的重複閱讀過程用,你對程式碼的理解會比上一次理解的更深刻,這樣你可以


修改那些註解錯誤的 地方和上一次沒有理解的對方。一般來說,對程式碼閱讀3,4次基本可以理解程式碼的


含義和作用。
執行並修改程式碼
  如果你的程式碼是可執行的,那麼先讓它執行起來,用單步跟蹤的方法來閱讀程式碼,會提高你的程式碼


速度。程式碼通過看中間變量了解程式碼的含義,而且對 以後的修改會提供很大的幫助
  用自己的程式碼代替原有程式碼,看效果,但在之前要保留原始碼
  600行的一個函式,閱讀起來很困難,程式設計的人不是一個好的習慣。在閱讀這個程式碼的時候將程式碼進


行修改,變成了14個函式。每一個大約是40-50 行左右.
———————————————原始碼下載網站—————————————————————
跟你說幾個我常用的原始碼下載網站
csdn(中文IT社群)它是集新聞、論壇、群組、Blog、文件、下載、讀書、Tag、網摘、搜尋、.NET、


Java、遊戲、視訊、人才、外包、第二書店、《程式設計師》等多種專案於一體的大型綜合性IT入口網站,


原始碼只是其中的一項,但是很實用 裡邊有很多大牛。
DevStore(原始碼下載)主要是開發者服務平臺,彙集國內外眾多第三方開發者服務,為開發者提供從設


計開發到運營推廣一站式的解決方案,原始碼和服務評測也是亮點,很專業,很實用,這裡邊聚集的都是


開發者和PM,可以看看。
站長之家(網站原始碼)針對個人站長,企業網管提供的資訊和原始碼,包含的語言和型別也比較多。


這個問題最好玩的地方就是在於一堆人喜歡東扯一點西扯一點 , 最後說拿eclipse來看看原始碼吧= =
真好玩.


工具就 vim + 一款自己熟悉的文字編輯器,關鍵是要選一個感興趣的子系統/模組開始


之前好像就答過 目標導向是閱讀一切原始碼的不二法門 試試給android系統慢慢加一下小功能 先從ui


開始 然後再往下深 期間沒準有彩蛋 遇到bug之類的 修掉提交給google吧


Eclipse裡看最方便了。在Android SDK的platforms目錄下建立sources資料夾,放入frameworks的源代


碼,Eclipse裡就能自動開啟原始碼了。網上有很多具體的說明。
如果是看所有原始碼,包括底層C/C++原始碼,可以用lxr,變數函式查詢和跳轉都非常方便,但配置起來比


較麻煩,需要多嘗試。


有沒有用記事本的?我就用Notepad++和SublimeText來看。搜尋用Everything和baregrep,以及


Notepad++的搜尋功能


多年的Android經驗建議,debug, debug & debug!
動態跟蹤android framework程式碼,屬於service實現的相關程式碼就attach到systemserver上
比你看死程式碼強N倍!


閱讀別人的程式碼作為開發人員是一件經常要做的事情。一個是學習新的程式語言的時候通過閱讀別人的


程式碼是一個最好的學習方法,另外是積累程式設計經驗。如果你有機會閱讀一些作業系統的程式碼會幫助你理


解一些基本的原理。還有就是在你作為一個質量保證人員或一個小領導的時候如果你要做白盒測試的時


候沒有閱讀程式碼的能力是不能完成相應的任務。最後一個就是如果你中途接手一個專案的時候或給一個


專案做售後服務的時候是要有閱讀程式碼的能力的。
  收集所有可能收集的材料
  閱讀程式碼要做的第一件事情是收集所有和專案相關的資料。比如你要做一個專案的售後服務,那麼


你首先要搞明白專案做什麼用的,那麼調研文件、概要設計文件、詳細設計文件、測試文件、使用手冊


都是你要最先搞到手的。如果你是為了學習那麼儘量收集和你的學習有關的資料,比如你想學習linux的


檔案系統的程式碼,那最好要找到linux的使用手冊、以及檔案系統設計的方法、資料結構的說明。(這些


資料在書店裡都可以找到)。
  材料的種類分為幾種型別
  1.基礎資料。
  比如你閱讀turbo c2的原始碼你要有turbo c2的函式手冊,使用手冊等專業書籍,msc 6.0或者java 


的話不但要有函式手冊,還要有類庫函式手冊。這些資料都是你的基礎資料。另外你要有一些關於uml的


資料可以作為查詢手冊也是一個不錯的選擇
  2.和程式相關的專業資料。
  每一個程式都是和相關行業相關的。比如我閱讀過一個關於氣象分析方面的程式碼,因為裡邊用到了


一個複雜的資料轉換公式,所以不得不把自己的大學時候課本 找出來來複習一下高等數學的內容。如果


你想閱讀linux的檔案管理的程式碼,那麼找一本講解linux檔案系統的書對你的幫助會很大。
  3.相關專案的文件資料
  這一部分的資料分為兩種,一個相關行業的資料,比如你要閱讀一個稅務系統的程式碼那麼有一些財


務/稅務系統的專業資料和國家的相關的法律、法規的資料是 必不可少的。此外就是關於這個專案的需


求分析報告、概要設計報告、詳細設計報告,使用手冊、測試報告等,儘量多收集對你以後的程式碼閱讀


是很重要的
  知識準備
  瞭解基礎知識,不要上來就閱讀程式碼,打好基礎可以做到事半功倍的效果
  留備份,構造可執行的環境
  程式碼拿到手之後的第一件事情是先做備份,最好是刻在一個光碟上,在程式碼閱讀的時候一點不動代


碼是很困難的一件事情,特別是你要做一些修改性或增強性維護的時候。而一旦做修改就可能發生問題


,到時候要恢復是經常發生的事情,如果你不能很好的使用版本控制軟體那麼先留一個備份是一個最起


碼的要求了。
  在做完備份之後最好給自己構造一個可執行的環境,當然可能會很麻煩,但可執行程式碼和不可執行


的程式碼閱讀起來難度會差很多的。所以多用一點時間搭建一個環境是很值得的,而且我們閱讀程式碼主要


是為了修改其中的問題或做移植操作。不能執行的程式碼除了可以學到一些技術以外,用處有限。
  找開始的地方
  做什麼事情都要知道從那裡開始,讀程式也不例外。在c語言裡,首先要找到main()函式,然後逐層


去閱讀,其他的程式無論是vb、delphi都要首先找到程式頭,否則你是很難分析清楚程式的層次關係。
  分層次閱讀
  在閱讀程式碼的時候不要一頭就紮下去,這樣往往容易只見樹木不見森林,閱讀程式碼比較好的方法有


一點象二叉樹的廣度優先的遍歷。在程式主體一般會比較簡 單,呼叫的函式會比較少,根據函式的名字


以及層次關係一般可以確定每一個函式的大致用途,將你的理解作為註解寫在這些函式的邊上。當然很


難一次就將全部注 解都寫正確,有時候甚至可能是你猜測的結果,不過沒有關係這些註解在閱讀過程是


不斷修正的,直到你全部理解了程式碼為止。一般來說採用逐層閱讀的方法可以是 你係統的理解保持在一