天天看點

C/C++ 入門建議

C/C++ 這門語言與其他進階語言不同,它是離作業系統較近的語言。是以學好 C/C++ 體系的技術棧必須結合作業系統的運作機制來學習。展開來說,就是你必須掌握作業系統層面的幾大基礎知識,他們是彙編、編譯連結與運作時體系、狹義的作業系統原理、多線程、網絡程式設計。

第一個基礎知識是彙編,我們學習彙編不是一定要用彙編來寫代碼,就像我們學習 C/C++ 也不一定單純為了面試和找工作。

對于 C/C++ 的同學來說,彙編是建議一定要掌握的,隻有這樣,你才能在書寫 C++ 代碼的時候,清楚地知道你的每一行C++代碼背後對應着什麼樣的機器指令,if/for/while 等基本程式結構如何實作的,函數的傳回值如何傳回的,為什麼整型變量的數學運算不是原子的,最終你知道如何書寫代碼才能做到效率最高。掌握了彙編,你可以明白,在 C++ 中,一個棧對象從構造到析構,其整個生命周期裡,開發者的代碼、編譯器和作業系統分别做了什麼。掌握了彙編,你可以了解函數調用是如何實作的,你可以了解函數的幾種調用方法,為什麼printf這樣的函數其調用方式不能是 __stdcall,而必須是 __cdecl。掌握了彙編,你就能明白為什麼一個類對象增加一個方法不會增加其實際占的記憶體空間。

推薦王爽老師的《彙編語言(第 3 版)》和《老碼識途 從機器碼到架構的系統觀逆向修煉之路 》。

第二個基礎知識是編譯、連結與運作時體系知識。作為一個開發者,要清楚地知道我們寫的 C/C++ 程式是如何通過預處理、編譯與連結等步驟最終變成可執行的二進制檔案,作業系統如何識别一個檔案為可執行檔案,一個可執行檔案包含什麼内容,執行時如何加載到程序的位址空間,程式的每一個變量和資料位于程序位址空間的什麼位置,如何引用到。一個程序的位址空間有些什麼内容,各段位址分布着什麼内容,為什麼讀寫空指針或者野指針會有記憶體問題。一個程序如何裝在各個 so 或 dll 檔案的,這些檔案被加載到程序位址空間的什麼位置,如何被執行,資料如何被交換。

推薦《程式員的自我修養》這本書。

第三個基礎知識是狹義的作業系統原理。這裡加上“狹義”二字是因為從廣義上來講,以上所說的内容都是作業系統原理的範疇。狹義的作業系統原理這裡包括作業系統如何管理程序與線程,虛拟記憶體與實體記憶體之間的對應關系,何為記憶體映射檔案,程序之間如何通信等等。

推薦《現代作業系統》這本書。

第四個基礎知識是多線程知識。嚴格來說,這點已經包括在第三點之中了,我之是以将其單獨列出來,是因為多線程程式設計是我們做應用服務最常用的技術之一。最近面試過幾個學曆非常好的同學,對于一個程序中如果某個線程因為記憶體問題而退出,是否會導緻整個程序退出的問題答不好,實在不應該。多線程知識其實不難學,立足于了解與實踐而不是應付面試,可以學的很好。無論是 Windows 還是 Linux 作業系統,作業系統提供的線程同步對象就那麼幾種,Windows 常用的有臨界區(關鍵端)、Event、互斥體、信号量等,Linux 有互斥體、信号量、讀寫鎖、條件變量,這些知識點學過則會,不學則不會。這些線程同步原語花上幾天就能搞得清楚,大多數同學不是學不會,而是不願意學,但是偏偏喜歡在履歷上寫上自己熟悉多線程程式設計。面試的時候,被問到條件變量的虛假喚醒機制都說不清楚,非要說自己用過條件變量。這是一些同學犯的很低級的錯誤,如果真用過條件變量,如果不知道虛假喚醒機制,那一定寫的代碼是不對的。

掌握了常見的多線程同步原語之後,接下來可以找一些帶多線程的項目去學習一下,不管是否帶 UI 的都行。我推薦的一種方式是,使用 gdb 或者 Visual Studio 調試器将你需要學習的多線程程式中斷下來,在多線程面闆,看看這個程序一共有多少個正在運作的線程,分析每個線程的作用,然後研究下這些線程在何時何地建立的,為什麼需要建立新的線程。嘗試愛過幾個人,面對愛情你會誠實很多;嘗試研究幾個多線程項目,面對多線程你會熟練許多。

第五個是網絡程式設計,直白地說就是 Socket 程式設計。作業系統層面提供的 API 會在相當長的時間内保持接口不變,一旦學成,終生受用。了解和掌握常用的基礎 socket API 不僅可以最大化地去定制各種網絡通信架構,更不用說使用市面上流行的網絡通信庫了,最重要的是,它會是你排查各種網絡疑難雜症堅實的技術保障。作業系統層面提供的網絡模型就那麼幾種,無論像 Java/Go/Python 等語言如何封裝,作為技術的源頭,我們有什麼理由不去掌握它呢?市面上關于網絡程式設計的書很多,我在書中結合我這些年的工作經驗總結了二十幾個網絡程式設計中的重點和難點,現在全部交給你。

推薦《TCP/IP 網絡程式設計》一書。

以上是基于 C++ 技術棧來說,并沒有包括算法與資料結構、資料庫等方面的基本功,但是這些額外的也是應該需要掌握的。