乙個c
語言程式到執行完檔案的全過程
在linux
裡面用gcc
編譯的程式時,編譯的過程可以細分為四個階段:
(1)預處理(pre-processing)
(2)編譯(compiling)
(3)彙編(assembling)
(4)鏈結(linking)
1.在預處理階段
「gcc -e test.c -o test.i」,其中,引數e
告訴gcc
命令值經行編譯,不做其他的處理,用引數
o指明輸出的檔名為
test.i
。命令執行完畢後就會產生乙個名為
test.i
的檔案。
編譯預處理主要是讀取c
源程式,對其中的偽指令(以
#開頭的指令)和特殊符號進行處理。
偽指令主要包括以下四個方面:
(1)巨集定義指令,如# define name tokenstring,#undef
等。對於前乙個偽指令,預編譯所要作得的是將程式中的所有
name
用tokenstring
替換,但作為字串常量的
name
則不被替換。對於後者,則將取消對某個巨集的定義,使以後該串的出現不再被替換。
(2)條件編譯指令,如#ifdef,#ifndef,#else,#elif,#endif,
等等。這些偽指令的引入使得程式設計師可以通過定義不同的巨集來決定編譯程式對哪些**進行處理。預編譯程式將根據有關的檔案,將那些不必要的**過濾掉。 (3
)標頭檔案包含指令,如
#include "filename"
或者#include
等。在標頭檔案中一般用偽指令
#define
定義了大量的巨集(最常見的是字元常量),同時包含有各種外部符號的宣告。採用標頭檔案的目的主要是為了使某些定義可以供多個不同的
c源程式使用。因為在需要用到這些定義的
c源程式中,只需加上一條
#include
語句即可,而不必再在此檔案中將這些定義重複一遍。預編譯程式將把頭檔案中的定義統統都加入到它所產生的輸出檔案中,以供編譯程式對之進行處理。包含到
c源程式中的標頭檔案可以是系統提供的,這些標頭檔案一般被放在
/usr/include
目錄下。在程式中
#include
它們要使用尖括號(
<>
)。另外開發人員也可以定義自己的標頭檔案,這些檔案一般與
c源程式放在同一目錄下,此時在
#include
中要用雙引號(
"")。 (4
)特殊符號,預編譯程式可以識別一些特殊的符號。例如在源程式中出現的
line
標識將被解釋為當前行號(十進位制數),
file
則被解釋為當前被編譯的
c源程式的名稱。預編譯程式對於在源程式中出現的這些串將用合適的值進行替換。 預編譯程式所完成的基本上是對源程式的「替代」工作。經過此種替代,生成乙個沒有巨集定義、沒有條件編譯指令、沒有特殊符號的輸出檔案。這個檔案的含義同沒有經過預處理的原始檔。
2.編譯階段
「gcc - s test.i -o test.s」,
其中引數s告訴
gcc命令只進行編譯,不做其他處理。命令執行完畢以後就會產生乙個名為
test.s
的彙編檔案。
編譯階段主要是經過預編譯得到的輸出檔案中,將只有常量。如數字、字串、變數的定義,以及c
語言 的關鍵字,如
main,if,else,for,while,,+,-,*,\
,等等。預編譯程式所要作得工作就是通過詞法分析和語法分析,在確認所有的指令都符合語法規則之後,將其翻譯成等價的中間**表示或彙編**。
3.彙編階段
「gcc -c test.s -o test.o」,
其中,引數c告訴
gcc命令只進行彙編,不做其他處理。命令執行完畢後就會產生乙個名為
test.o
的目標檔案。
彙編過程主要的作用是彙編過程實際上指把組合語言**翻譯成目標機器指令的過程。對於被翻譯系統處理的每乙個c
語言源程式,都將最終經過這一處理而得到相應的目標檔案。目標檔案中所存放的也就是與源程式等效的目標的機器語言**。目標檔案由段組成。通常乙個目標檔案中至少有兩個段: **段 該段中所包含的主要是程式的指令。該段一般是可讀和可執行的,但一般卻不可寫。 資料段 主要存放程式中要用到的各種全域性變數或靜態的資料。一般資料段都是可讀,可寫,可執行的。
unix
環境下主要有三種型別的目標檔案: (
1)可重定位檔案 其中包含有適合於其它目標檔案鏈結來建立乙個可執行的或者共享 的目標檔案的**和資料。 (
2)共享的目標檔案 這種檔案存放了適合於在兩種上下文裡鏈結的**和資料。第一 種事鏈結程式可把它與其它可重定位檔案及共享的目標檔案一起處理來建立另乙個目標文 件;第二種是動態鏈結程式將它與另乙個可執行檔案及其它的共享目標檔案結合到一起, 建立乙個程序映象。 (
3)可執行檔案 它包含了乙個可以被作業系統建立乙個程序來執行之的檔案。 匯程式設計序生成的實際上是第一種型別的目標檔案。對於後兩種還需要其他的一些處理方能 得到,這個就是鏈結程式的工作了。
4.鏈結階段
「gcc test.o -o test」,
執行完成後就會產生乙個名為
test
的可執行檔案。
鏈結程式 由匯程式設計序生成的目標檔案並不能立即就被執行,其中可能還有許多沒有解決的問題。例 如,某個原始檔中的函式可能引用了另乙個原始檔中定義的某個符號(如變數或者函式調 用等);在程式中可能呼叫了某個庫檔案中的函式,等等。所有的這些問題,都需要經鏈 接程式的處理方能得以解決。 鏈結程式的主要工作就是將有關的目標檔案彼此相連線,也即將在乙個檔案中引用的符號 同該符號在另外乙個檔案中的定義連線起來,使得所有的這些目標檔案成為乙個能夠被作業系統裝入執行的統一整體。
靜態鏈結:
字尾是.a
,主要在編譯的時候將庫檔案裡面**搬遷到課執行的檔案中;
主要在執行的時候將需要的庫檔案**搬遷到可以執行的檔案中;
(1)靜態的鏈結產生的可執行的檔案體積比較的大;而動態鏈結的可執行檔案的體積比較小;
(2)動態的鏈結的編譯的效率比較的高;
(3)靜態鏈結的可執行的檔案執行的效率高
(4)靜態鏈結的可執行的檔案的「布局」比較好一點;
動態鏈結更加適合頻繁更新的
乙個c語言程式
include include include void shuffle int wdeck 4 13 void deal int wdeck 4 13 char wface 13 char wsuit 4 int main char wface 13 int wdeck 4 13 printf 這...
乙個C 程式的執行過程
可能很多人都知道我們把程式打包成dll就丟出去了,但是裡面的具體的執行過程是怎麼樣的呢。程式集是由元資料和il組成的。il是和cpu無關的語言,是微軟的幾個專家請教了外面的編譯器的作則,開發出來的。il比大多數機器語言都要高階一點。il能夠訪問和操作物件型別,並提高了指令來初始化物件,呼叫物件上的虛...
乙個出錯的C語言程式
include stdio.h double function double total,double i,double j main else sum function total,i,j printf lf sum double function double total,double i,do...