本節書摘來自異步社群《c程式設計新思維》一書中的第1章,第1.7節,作者 【美】ben klemens,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視
到此,你應該已經看出編譯過程的套路了。
1. 設定一個表述編譯器選項的變量。
2. 設定一個表述連接配接器選項的變量,包括為你用的所有庫配置的-l選項。
3. 用make指令或者你的ide的操作來把這些變量轉換為完整的編譯和連接配接指令。
本章的餘下部分将把以上步驟做最後一次,并采取一種非常簡短的設定:僅僅用shell。如果你思維靈活,可以通過摘錄一些語句段落到解析器上來學習腳本,你也将可以同樣地把c代碼貼在你的指令行上。
**
1.7.1 在指令行裡包含頭檔案**
gcc和clang有一個用于包含頭檔案的友善的配置。例如:

這和在c源檔案的開頭放入下面這行等價的:
同樣地也可以用clang –include stdio.h。
通過把以上加入我們的編譯器調用,最終我們可以把hello.c程式寫成隻有一行:
通過以下方式順利編譯:
或者利用shell指令:
這個關于-include的竅門是随編譯器不同的,并且把資訊從代碼轉移到編譯指令中。如果你認為這是一個壞習慣,那好,就忘了它吧。
1.7.2 統一的頭檔案**
很久以前,編譯器處理一個哪怕不算複雜的程式要也要花費好幾秒甚至幾分鐘的時間,是以減少一些編譯器不得不做的工作,可以産生一些顯而易見的好處。我現在的stdio.h和stdlib.h每個都有1,000多行(可以用wc –l /usr/include/stdlib.h驗證),time.h也有400行,這就意味着下面這個僅7行的小程式,實際上是一個大約2,400行的程式:
而今,編譯器已經不再以為2,400行是一個大問題,這種編譯也就花費不到1秒。那麼我們為何還要花時間去為一個特定的程式挑選正确的頭檔案呢?
如果你是一個gcc或clang使用者,當你擁有一個統一的頭檔案後,你就不必再書寫甚至隻有一行#include 的類似代碼,因為你可以在cflags中用-include allheads.h來代替它,然後不用再擔心與項目無關的頭檔案了。
自己動手:為自己寫一個通用的頭檔案,讓我們稱之為allheads.h,然後把你用過的所有頭檔案都扔到裡面去,那麼它就将看起來像:
我其實無法告訴你它确切長得什麼樣,因為我不知道你每天都用什麼檔案。
現在你有了這個內建的頭檔案,隻需在所有檔案的開頭加上這麼一句:
.這樣你就不用再操心頭檔案了。的确,加上這個頭檔案會擴充出10,000行額外的代碼,而且其中大多數和手頭的程式無關。但是你不會留意到,而且沒用的聲明也不會改變最終的可執行檔案。
頭檔案還可以起到限定作用域的目的,但是這個通常在你寫函數和結構時更重要,而不是對于那些庫。作用域限定範圍的目的不是為了縮小命名空間以防止計算機過熱;而是為了減少作為程式員的你的認知負擔。我猜你甚至都不熟悉你所使用的庫中的大部分的函數,如果你都不了解,那麼它們也不可能帶來任何認知負擔。其他的語言甚至不做區分并有成堆的關鍵詞,比如r項目,就有752個啟動時内部定義的關鍵詞。
1.7.3 嵌入文檔
嵌入文檔是posix标準的shell的一個特性,你可以用在c、python、perl,或者别的什麼中,他們也使得這本書更加有用和有趣。并且,如果你想要有一個多語言的腳本,嵌入文檔是一個實作的友善法門。在perl中做解析,在c語言中做算數,然後用gnuplot産生漂亮的圖檔,并且內建在一個文本檔案裡。
這是一個python的例子。通常,你通過下面的方法告訴python去運作一個腳本:
你可以使用‘-’以使用stdin作為輸入檔案:
這裡要用'-'而不僅僅是-,表明這是一個純文字,而不是一個用來引出類似python–c “print ‘hi’”中的c的開關。許多程式遵從gnu的習慣,使用兩個橫線來表示停止讀取開關并把随後的輸入讀取為純文字。是以:
也會起作用,但是這類事情會吓到大家。
理論上,你應該通過echo把一些過長的腳本放到指令行上,但是你很快就會看到有很多短小、不符合期望的解析在進行——比如,你可能需要用”hi”而不是”hi”。
那麼,嵌入文檔實際上根本就不會被解析。比如:
嵌入文檔是一項标準的shell特性,是以它們應該在任何posix系統中都可以用。
“xxxx”代表你想用的任何字元串;“eof”也很流行,而“-----”隻要你把連字元的數量和頂部和底部都配合得很好的話,看起來也還不錯。當shell看到你標明的字元串單獨占一行,它會停止向stdin輸出腳本。這就是一般腳本解析的過程。
還有以<<-開始的變體。這種變體去掉了所有的每行開頭的tab鍵,是以你可以把一個漸次縮進的shell腳本文檔放在這裡,而不會打短縮進的流程。當然,這對python的嵌入文檔而言是一個災難。
作為另一個變體,<<”xxxx”和<1.7.4 從stdin中編譯
現在,回到c的世界中來:我們可以用嵌入文檔來編譯通過gcc或clang貼到指令行的c代碼,或者在一個多語言的腳本中的幾行程式。
我們不再用makefile,是以我們需要一個單行的編譯指令。為了讓生活變得不那麼痛苦,讓我們給它起個别名。把它輸出到你的指令行,或者把它添加在你的.bashrc、.zshrc,或者任何适合的地方:
這裡的allheads.h是你之前放在一起的內建的頭檔案。當你寫c代碼的時候,用-include選項是你最不應該考慮的事情,并且我也發現當c代碼中出現#的時候,bash的曆史變得有點靠不住。
在編譯行,你将認出 '-' 意味着用stdin而不是從一個命名的檔案輸入。-xc認為這是c代碼,因為gcc代表gnu編譯器組合,而不是gnu c編譯器,也沒有類似.c的輸入檔案名來提示它,我們必須指明這不是java、fortran、objective c、ada,或者c++(對clang也一樣,即使它的名字是有意在提示是c語言)。無論你在makefile中對ldlibs和cflags做了多少客制化,這裡也要做。現在你已經揚帆出海了,可以在指令行中編譯c代碼了:
我們可以使用嵌入文檔來粘貼簡短的c程式到指令行,并寫一點帶有争議性的測試程式。不僅是你不需要一個makefile,你甚至也不需要一個輸入檔案。
不要認為這種事情就是你的基本工作狀态。但是剪切粘貼代碼段落到指令行是有趣的,并且在一個較長的shell腳本内可以用一步完成c也是非常棒的。
[1] gui——圖形使用者界面,如目前常見的windows、ios等作業系統。——譯者注
[2] cygwin有red hat, inc.營運的項目,該公司也允許使用者購買不按照gpl版權釋出自己源代碼的權利。
[3] 雖然msys、mingw和一些其他作為包提供,這些包的數量與典型的包管理器提供的上百個包相比顯得很蒼白。值得注意的是,預編譯的庫并不是點選一下或者輸入一個指令行就可以被安裝好的。不過,當你讀到這些的時候,我的抱怨可能已經被解除了,也就是說有了更多的mingw包可用。
[4] 借用最新出現的grunge rock風格,指代最新的c編譯器——譯者注