1. 程式人生 > >不簡單的hello world之C標準庫(第一部分)

不簡單的hello world之C標準庫(第一部分)

目錄

5 庫的分類

C標準庫

在上一篇文章當中我們分析了hello world這個程式的第一行,那麼我們接下就開始看後面的程式碼,可能有人會說了,這麼簡單的程式碼還有什麼可看的,同學們,有句話說的非常好,魔鬼在細節,那麼這個魔鬼在這裡就是printf函式。

printf人人都會用,從寫hello world就開始用,用了這麼多年簡直是使用最多的函式,除錯bug的必備利器,但是,親愛的同學,你有沒有想過就是這個我們習以為常當做空氣一樣存在的的函式到底是怎麼實現的,它在哪裡被實現的,這個函式的實現檔案我們都沒有看到過,

那麼我們的hello world到底又是怎麼呼叫到這個函式的呢,printf到底是怎麼把hello world打在螢幕上讓我們看的呢,這些你能詳詳細細的說清楚嗎?如果你還不能清楚明白的解釋這些問題,這些問題對你還是一團迷霧的話,那麼接下來的我會在後面的文章當中一一為大家詳細講解。

說這些希望大家能保持一顆好奇的心,本質上這也是人類文明得以發展到今天的原因,如果牛頓對蘋果落地也像大家對printf習以為常一樣,我想萬有引力定律可能要向後推遲很多年了,牛頓萬有引力的發現絕對是影響人類文明的里程碑事件,具體為什麼就不在計算機課程上展開說了,概括的說就是萬有引力的發現讓人們第一次認識到大自然也是有規律從此解放了長期禁錮歐洲人思想由此誕生了一批猛人極大的推動了文明的發展之類,具體請參考西方歷史哲學史自然科學史等一系列史字結尾的書以及類似課程。在這個快節奏高壓力的現代生活中,很多人包括我自己有時都會感到迷茫,雖然外在環境如此,寫這些還是希望大家能在自己內心能保留一方淨土,在這片淨土上你依然有著這採菊東籬下悠然見南山的怡然自得,在你深夜加班回家後還能擡頭看一看天上的星空,你還能靜下心來好好思考一些問題,請保持珍貴的好奇心。

抒情完畢。

現在是時候給大家介紹一下關於這一主題隱藏在冰山之下的一部分,這一部分叫做C標準庫(C standard library)。

介紹一下標準庫,這個所謂的標準庫希望大家能理解一下,所謂標準庫,首先它是一個庫,那庫又是什麼呢,電腦科學當中有好多術語,一聽上去真的很唬人,這些很唬人的詞往往讓初學者誤以為這個東西一定很高深,很難,而那些已經理解這些詞語的人為了讓後來者也認為這些真的很高深很難所以往往不做任何解釋,其中一些術語你肯定很熟悉 比如這裡的庫,socket,面向連線,stream等等,我永遠都不能理解為什麼國內的作者不管是自己寫的技術書籍還是翻譯過來的就不能好好解釋一下這些名詞,我覺得計算機學習起來還是有一定的門檻的,這其中的一部分就在於計算機文化方面,這就類似於我們很難理解比如零零後喜歡的二次元,裡面有很多術語往往讓人一頭霧水一樣,這些文化上的阻隔會成為進入這個領域的第一道障礙,在這裡我會盡力用易懂的方式給大家講清楚這些很唬人的詞語到底是什麼意思。

1. 庫(Library)的定義

讓我們首先來看看到底什麼才是庫,總結起來一句話就是:

別人(或者自己)已經寫好的現成可用的一堆可重複使用的程式碼

這就是庫定義了,這裡的一堆程式碼可以是針對某個特定功能的程式碼,比如專用於數字分析計算的庫,可以是實現某些功能的框架(至於什麼是框架呢,見文章末尾),比如一些圖形庫,Libevent之類,也是可以自己積累的一些小工具,比如實現字串操作之類功能,這些都可以稱之為庫。個人覺得其原本的英文更形象一下,Library本來就是圖書館,書庫,資料室之類的意思,所以可以形象的把庫理解為相關主題的資料,書籍,如果你想了解(使用)一些特定的主題,只需要找相關的書籍資料就可以了,和這裡的庫的意思是一樣的。

介紹完了什麼是庫,那麼你可能會想,到底我們為什麼需要用到庫這麼個東西呢,那接下來首先來回答一下這個很重要的問題。

2. 為什麼需要庫

一個人的力量終歸是有限的,我們每個人都不是孤島,總需要和其它人一起協作來完成某項工作,對於程式設計,也是同樣的道理,如果某些我們需要的功能別人已經實現實現了,我們直接來用就好了。

為什麼需要庫總結下來就是一句話:

站在其它人的肩膀之上

很明顯這裡改編自著名大物理學家牛頓的名言,在被問及為什麼能取得如此巨大的成就時,牛頓謙虛的說到自己只是“站在了巨人的肩膀之上”,以牛頓學術成就如此之人尚且需要藉助於其它人的研究成果,作為平凡的勞苦大眾之廣大碼農更是沒有理由不去借助於其它人的程式碼了。

在計算機世界當中,庫,就是其它人的肩膀

我們使用的C標準庫,程式所執行之上作業系統(從某種角度上看,作業系統也可以看做庫,因為沒有作業系統的話,如果我們想執行一個程式還要自己來管理CPU,記憶體等硬體資源) ,處理網路資料的TCP/IP協議棧(你在寫socket程式的時候從沒有關心如何處理tcp協議丟包如何處理,如何進行超時重傳等等吧,同樣TCP/IP協議棧也可以看做是庫),因為TCP/IP協議棧已經把這些最複雜最瑣碎的工作給你完成了,當你在寫自己的程式時只需要專注於完成自己的事情就可以了,其它的事情交給完成特定功能的庫就可以了。

所以這下你應該明白了吧,我們每個人都不是萬能的,總有我們擅長的和不擅長的,寫程式也是這樣,比如我需要一些能進行矩陣運算的函式,但是自己實現起來太複雜了,而與此同時又有這樣的可以進行科學計算的現成的庫,那那我們為什麼不直接使用這些已經歷經考驗的高效優秀的庫呢,使用現成的庫可以大大加快專案專案的開發進度,目前國內很多網際網路公司,很多專案都是直接使用優秀的開源實現,在此基礎之上實現業務邏輯,從而實現專案的快速開發,快速迭代,這些都是通過藉助其它人的程式碼來實現的。所以說,某項自己想要的功能如果其它人已經實現了,而且實現的還不錯,那為什麼不直接只是用呢,而是用其它人的程式碼多是是以庫的形式來使用的,所以:

人生苦短,我們用庫

(注意這裡的意思是讓大家不要去造輪子(庫),但是知道一些輪子是如何造出來的還是很重要的,比如作業系統,比如計算機網路,或者對於任何你感興趣的庫我都鼓勵大家去看看到底是怎麼實現的,但是對於工程專案來說,還是那句話,不要造輪子,除非當前的輪子已經不適用於你的車速了)

我們在這一節中瞭解了為什麼需要庫,那麼庫是如何生成的呢? 接著往下看。

3. 庫是如何生成

讓我們先來猜猜,庫是如何生成,既然我們在上一節中說過,其它人的程式碼多是以庫的形式釋出的,那麼庫就是由程式碼生成的。可能很多人都說,這不是廢話嗎,是的,這種看似廢話的推理往往都是直白簡單的,而簡單的東西不容易出錯,這種這種不易出錯的推理正是我們一步一步進行探索的重要基礎。

說到這裡就不得不說一下原始檔和目標檔案(Object File)了。

我們知道,CPU不能執行if...else...,int a = b+c,等等這樣的我們人類能看懂的程式,CPU可以執行的恰恰是我們人類及其不容易看懂的二進位制指令01011000等等,從這些基本常識中我們就可以知道了,既然我們寫的是if...else...,int a = b+c等等這樣人類能看懂的程式,而且我們寫的這些程式CPU還能執行起來,那麼必然需要某個什麼東西把我們寫的程式碼翻譯成CPU能看懂的01二進位制指令,,而執行程式翻譯工作的翻譯官就是一個叫做編譯器的東西,我們寫的程式被編譯器翻譯過來給CPU看的就叫做目標檔案(Object File),如圖所示:

我們寫的每個.c檔案檔案都叫做原始檔,每個原始檔別翻譯官編譯器翻譯後生成的檔案是目標檔案,注意原始檔和目標檔案是一一對應的。每個原始檔當中就是我們寫的人類可讀的程式碼啦,而目標檔案當中對應的就是CPU可以讀懂的二進位制二進位制指令啦。你可以簡單的理解原始檔就是中文,而目標檔案就是對應的英文,而CPU只能看懂英文(當然,希望有朝一日,CPU也能讀懂中文)。

有的同學可能會問,那標頭檔案(include File)呢,請對此還不太瞭解的同學參考我的上一篇文章叫做《不簡單的Hello World之標頭檔案》,那裡面會有關於標頭檔案的詳細描述。簡單的說就是,編譯器不會編譯標頭檔案,標頭檔案的處理是一個叫做預編譯器的東西來完成的。編譯器只處理原始檔,然後把原始檔中的程式翻譯成二進位制檔案生成對應的目標檔案。

既然我們瞭解了原始檔以及對應的二進位制指令目標檔案,那麼我們就可以接下里給大家介紹一位計算機世界當中的幕後英雄了,這也是冰山水面之下的一位重量級選手,它就是連結器(Linker)。從名字當中你應該能猜出來它做什麼的,連結器嘛,主要就是把一些東西給拼裝起來的。連結器拼裝的是什麼呢,連結器拼裝的就是上面我們介紹的目標檔案(Object File)。

連結器的作用就是把編譯器翻譯的多個原始檔生成的多個對應的目標檔案打包起來生成一個檔案。這就是庫,從這裡同學們應該看出來了吧,庫裡面包含了我們原始檔裡的所有程式碼了,更重要的是,更重要的是什麼呢,同學們看出來了嗎,更重要的是,這個連結器連線好生成的單獨的一個檔案庫裡面已經就是CPU能看懂的二進位制指令了,有的同學又會問了,為什麼呢,因為連結器連線的是目標檔案啊,如圖上面圖所示,我們上面也說過目標檔案裡面就是翻譯官編譯器翻譯的CPU能讀懂的二進位制檔案了,既然庫裡面就已經是程式的二進位制形式了,所以這裡有一個好處,那就是,當我們使用庫的時候就省去了編譯這樣一個環節,要知道在大型專案中,編譯時間動不動就是幾十分鐘一個小時,所以提前把一些模組編譯成庫可以極大的縮短編譯時間。關於庫是如何生成的,這下你應該看明白了吧。這裡關於連結器的介紹是很隆重的,但是描述是很簡短的,這麼重要的利器只簡單介紹這麼一點這麼可以呢,太不給連結器(Linker)面子了吧,彆著急,我會在下一篇文章當中用整整一章來給大家詳細講解連結器(Linker),敬請期待。

由於本篇文章較長,我會在下一篇文章當中繼續後面的內容。同時希望大家關注我的公共賬號:碼農的荒島求生,那裡會有最近的系列文章,我會用最直觀最形象的方式給大家講解各種計算機知識,如果哪裡沒有看明白希望大家能在評論區中提出改進意見,我會持續進行修改,直到大家都能很容易的看明白為止,謝謝大家。

未完待續...

4 庫裡面有什麼

5 庫的分類

6 如何建立庫

7 什麼是標準庫

8 標準庫的優點