1. 程式人生 > >VS新增lib以及對編譯過程的總結

VS新增lib以及對編譯過程的總結

本來是想在VS2013新增一個lib的。由此認識到對編譯的原理認識不清楚,所以記錄一下

先說在vs中新增lib庫的方法:

通過設定工程來新增lib庫:

1.新增一個專案,右鍵屬性,改變 配置屬性----常規 中的配置型別為靜態庫或者動態庫,然後可以改變輸出目錄(指定一下庫目錄),此步驟就設定成了一個lib庫

2.在專案中使用,也需要設定屬性,因為要保證找到標頭檔案和庫檔案,所以在 配置屬性-----VC++ 下,加上包含目錄(標頭檔案目錄路徑)和庫目錄(生成的庫目錄路徑),然後在 連結器-----輸入 中新增 附加依賴項(庫名)

以上步驟可以建立一個公用庫,以方便不同專案呼叫

接下來是對編譯原理的一些總結:

借鑑了以下幾篇博文:

編譯原理:http://www.cnblogs.com/pipicfan/archive/2012/07/10/2583910.html

C++/C連結過程詳解:http://blog.sina.com.cn/s/blog_65fbc556010162j6.html

C標頭檔案與庫檔案的區別:http://blog.chinaunix.net/uid-27575921-id-4078661.html

標頭檔案中只能有宣告,不能放定義:http://blog.sina.com.cn/s/blog_6648c114010130ry.html

編譯的四個過程:

1.預處理

預處理C語言程式從原始碼變成可執行程式的第一步,主要是C語言編譯器對各種預處理命令進行處理,包括標頭檔案的包含、巨集定義的擴充套件、條件編譯的選擇等。


2.編譯

編譯之前,C語言編譯器會進行詞法分析、語法分析(-fsyntax-only),接著會把原始碼翻譯成中間語言,即組合語言。如果想看到這個中間結果,可以用-S選項。

3.彙編

把作為中間結果的彙編程式碼翻譯成了機器程式碼,即目的碼,不過它還不可以執行。如果要產生這一中間結果,可用gcc-c選項,當然,也可通過as命令_彙編_組合語言原始檔來產生。

4.連結

連結是處理可重定位檔案,把它們的各種符號引用和符號定義轉換為可執行檔案中的合適資訊(一般是虛擬記憶體地址)的過程。連結又分為靜態連結和動態連結,前者是程式開發階段程式設計師用ld(gcc實際上在後臺呼叫了ld)靜態連結器手動連結的過程,而動態連結則是程式執行期間系統呼叫動態連結器

(ld-linux.so)自動連結的過程。

由此我又想到標頭檔案和庫檔案有什麼區別,為什麼標頭檔案只能有宣告,不能有定義,#ifndef不就是來防止標頭檔案重複載入的嗎?

標頭檔案用於存放對型別定義、函式宣告、全域性變數宣告等實體的宣告,作為對外介面;而源程式檔案存放型別的實現、函式體、全域性變數定義。

標頭檔案中為什麼不能有定義:
首先必須瞭解編譯的過程,編譯的第一步是把所有的CPP檔案編譯成為點O檔案,而且每一個點CPP檔案都是單獨編譯的,該點CPP檔案中用到的型別必須在它所include 的標頭檔案當中找到,相當於把它所有include的檔案中的程式碼都加到該CPP檔案的前面,但是宣告的部分將不會出現在編譯後的點O檔案,相當於每個CPP檔案都是單獨編譯,因此它的ifndef在一個檔案裡是沒有用的,兩個CPP檔案裡如果包含同一個有ifndef的標頭檔案,效果是兩個CPP檔案都把該標頭檔案加到它的前面,但不會把宣告的部分放到點O檔案中,而會把標頭檔案中定義的部分都輸出到編譯後的點O檔案當中
因此如果在標頭檔案當中有一個定義,那麼如果有兩個CPP檔案當中include了它,那麼將會出現重定義錯誤,multiple definition of。

那麼#ifndef做什麼呢?

我覺得#ifndef只能防止兩個包含了一個基 標頭檔案,但在一個檔案中卻同時包含了這兩個標頭檔案,這個時候是可以防止重複載入的,相當於C++的多重整合,虛繼承就是保證只繼承到一個基類。

來做個總結:

我們在程式中要保證的是能找到標頭檔案和庫檔案

那麼預處理階段就是找到標頭檔案並將其原封不動的載入到當前檔案中:

#include載入標頭檔案
< >引用的是編譯器的類庫路徑裡面的標頭檔案
" "引用的是你程式目錄的相對路徑中的標頭檔案

當然在linux中也可以用-I選項指定標頭檔案路徑

有了標頭檔案中的宣告,就可以進行詞法分析、語法分析了

而庫檔案是連結的時候所需要的,所以我們可以放到標準路徑或者用-L指定路徑,當然也可以修改環境變數,連結將多個目標檔案整合成一個可執行檔案。

當然,動態庫是在執行時載入的,所以執行時仍需要知道庫路徑,此時可以修改環境變數,或者放到標準庫目錄中

關於原始檔中應不應該include此原始檔對應的標頭檔案,如果需要有宣告的地方那麼是需要加標頭檔案,比如.h中有兩個函式的宣告,.cpp中其中一個函式呼叫了另外一個,此時就需要宣告,所以需要加標頭檔案

不然也不用加,因為只是簡單的替換
比如:.h檔案中宣告一個函式,.cpp中實現這個函式,那便不用加

因為在連結之前都是單獨編譯的,在連結時整合程式碼,如果一個專案中有多個同名函式且引數也相同時(C++支援過載),那麼就需要名稱空間了,來具體指出是哪個庫檔案。

寫的比較亂,請諒解,有機會再改