C 的編譯和鏈結

2021-10-25 15:01:46 字數 2460 閱讀 9057

之前一直沒能理解c++編譯的邏輯,所以我一直很好奇,主程式的cpp檔案裡只註明了h標頭檔案,而標頭檔案跟cpp檔案也並不要求一一對應,那麼編譯的時候,系統到底是如何從**件往回找到相對應的函式原始檔呢?

現在搞明白了,這裡會用g++來做乙個簡單的邏輯梳理。

g++是linux下最常用的編譯工具,而在windows系統中,我們常直接使用vs等軟體自帶編譯器進行編譯,其實是一樣的。

#include

#include

intmain()

通常情況下,我們編譯這個程式是用這個指令

g++ test.cpp -o test
而從完整的邏輯上來講,cpp檔案的編譯要經過四個階段,分別是預處理(preprocessing)、編譯(compilation)、彙編 (assembly)和鏈結(linking)。

2.1 預處理(preprocessing)

g++

-e test.cpp -o test.i

或者

g++

-e test.cpp

第一句指令會輸出test.i檔案,而第二句指令會直接將結果從視窗輸出。通過輸出結果我們就可以知道,預處理的其中乙個作用,其實就是把頭檔案全部複製到test檔案中來。

更準確的說,這一步會處理的是preprocessing語句,包括include、defind、 if 等等,換而言之,我們為了方便而將程式拆成了各個不同的模組或者表達方式,而preprocessing是反過來,將我們寫成的這些程式重新生成乙個完整的整體。

很多時候,程式中所包含的標頭檔案中,又會包含新的標頭檔案,特別是像iostream這種。所以,為了控制檔案的大小,我們要盡量避免多餘的標頭檔案。

2.2 編譯(compilation)

g++

-s test.i -o test.s

這裡是對生成的test.i檔案編譯,生成彙編**。

所以雖然我們所寫為c++,但實際上到機器執行時,還是先需要轉化成彙編**,才能進行下一步編譯。

2.3 彙編 (assembly)

g++

-c test.s -o test.o

將上一步生成的彙編**進行編譯,編譯成機器**。

2.4 鏈結(linking)

g++ test.o -o test
負責將程式的目標檔案與所需的所有附加的目標檔案連線起來,這個時候只需要執行test檔案,就可以實現** hello,world。

2.5 error

在我們編寫程式後進行一步到位的編譯時,經常會出錯,那麼理解了編譯的四個環節之後,我們就可以簡單的去理解一些問題的原因。例如:

如果報錯error c***x:那麼就是編譯(compilation)出現了錯誤,一般是函式等未做宣告

如果報錯error link***x: 那麼就是鏈結(linking)出現了錯誤,一般是未找到函式的定義。

2.6 編譯優化

編譯優化並非一定會進行的,不過這裡也順便講一下(例子)

程式優化的內容包括:與程式 毫不相關的函式、多餘的引數變數,消除多餘步驟等。不同等級的優化程度不一樣,一般o2就夠了,o3以上有時候會出現編譯時間長,編譯失敗等現象。

當我們需要同時進行多個cpp檔案編譯時。例如:

log.h

void

log(

const

char

* msg)

;

log.cpp

#include

void

log(

const

char

* msg)

test.cpp

#include

#include

'log.h'

intmain()

那麼這個時候,如果按照我們一開始的邏輯,使用函式時會遍歷資料夾的所有cpp檔案去找相對應的函式,那麼我們的程式也應該是g++ test.cpp -o test。但根據我們梳理的四個步驟,可以發現實際上並不應該這麼寫,這麼寫的話,只有log.h跟test.cpp被納入編譯的初始檔案。正確的編譯指令應該這麼寫

g++ log.cpp test.cpp -o test
而這樣的話,我們就會迎來乙個新的問題,如果乙個專案檔案很多,我們根本不可能像這樣乙個檔案乙個檔案的去輸入來編譯,這樣效率太慢了,所以就有了cmakelist的出現。

在各種專案資料夾中,我們都可以看見他,可以簡單的理解成乙個批量編譯的指令碼

理解了編譯的過程,那麼還將有伴隨而來的新的問題,都將在後面一一處理。

1、cmakelist的書寫

2、如果多個cpp檔案都用到同乙個**件,那麼編譯的時候不就會被重複編譯?

3、函式的宣告和定義?

C 編譯和鏈結

我的個人部落格 乙份源 要生成乙份可以執行的程式,需要經過的步驟就是編譯和鏈結。c語言的源 一般以.c和.h結尾,其中的c語言 屬於比較高階的語言,人類可以很輕易的看懂,但是計算機並不能理解,也不能直接執行。計算機只能識別二進位制的資料,c 這種類似於人類自然語言的高階語言,它是不能識別的。所以c語...

C 編譯鏈結

過程 一 預編譯 預處理 處理 define if include這類 開頭的語句,這些稱為預編譯指令。這個過程中會把.h檔案和.c cpp檔案組合成最終交給compile過程的原檔案。這個原檔案是不包含任何 開頭的語句的。所有 define定義的巨集也會被替換。二 編譯 把上面那個原檔案編譯成.o...

C 編譯 鏈結

c 程式在編譯的時候主要有以下幾個過程 1.預編譯 預處理 主要是對偽指令 以 開頭的指令 和特殊符號進行處理。偽指令主要包括 1 巨集指令 如 define name adu,undef等。對於第乙個指令,預編譯主要是進行替換,除了name字串常量 對於第二個則取消該巨集定義,以後出現該巨集的地方...