C/C++程序編譯過程詳解

原文地址:https://www.cnblogs.com/mickole/articles/3659112.html

C語言的編譯鏈接過程要把我們編寫的一個c程序(源代碼)轉(zhuǎn)換成可以在硬件上運行的程序(可執(zhí)行代碼),需要進(jìn)行編譯和鏈接其兴。編譯就是把文本形式源代碼翻譯為機器語言形式的目標(biāo)文件的過程。鏈接是把目標(biāo)文件、操作系統(tǒng)的啟動代碼和用到的庫文件進(jìn)行組織,形成最終生成可執(zhí)行代碼的過程扩灯。過程圖解如下:

從圖上可以看到媚赖,整個代碼的編譯過程分為編譯和鏈接兩個過程,編譯對應(yīng)圖中的大括號括起的部分珠插,其余則為鏈接過程惧磺。

1. 編譯過程

編譯過程又可以分成兩個階段:編譯和匯編。

編譯

編譯是讀取源程序(字符流)捻撑,對之進(jìn)行詞法和語法的分析磨隘,將高級語言指令轉(zhuǎn)換為功能等效的匯編代碼,源文件的編譯過程包含兩個主要階段:

編譯預(yù)處理

讀取c源程序顾患,對其中的偽指令(以# 開頭的指令)和特殊符號進(jìn)行處理番捂。

偽指令主要包括以下四個方面:

  1. 宏定義指令,如# define Name TokenString描验,# undef等白嘁。

對于前一個偽指令,預(yù)編譯所要做的是將程序中的所有Name用TokenString替換膘流,但作為字符串常量的 Name則不被替換絮缅。對于后者,則將取消對某個宏的定義呼股,使以后該串的出現(xiàn)不再被替換耕魄。

  1. 條件編譯指令,如# ifdef彭谁,# ifndef吸奴,# else,# elif缠局,# endif等则奥。

這些偽指令的引入使得程序員可以通過定義不同的宏來決定編譯程序?qū)δ男┐a進(jìn)行處理。預(yù)編譯程序?qū)⒏鶕?jù)有關(guān)的文件狭园,將那些不必要的代碼過濾掉读处。

  1. 頭文件包含指令,如# include "FileName" 或者# include < FileName> 等唱矛。

在頭文件中一般用偽指令# define定義了大量的宏(最常見的是字符常量)罚舱,同時包含有各種外部符號的聲明。

采用頭文件的目的主要是為了使某些定義可以供多個不同的C源程序使用绎谦。因為在需要用到這些定義的C源程序中管闷,只需加上一條# include語句即可,而不必再在此文件中將這些定義重復(fù)一遍窃肠。預(yù)編譯程序?qū)杨^文件中的定義統(tǒng)統(tǒng)都加入到它所產(chǎn)生的輸出文件中包个,以供編譯程序?qū)χM(jìn)行處理。

包含到c源程序中的頭文件可以是系統(tǒng)提供的冤留,這些頭文件一般被放在/ usr/ include目錄下赃蛛。在程序中# include它們要使用尖括號(< >)恃锉。另外開發(fā)人員也可以定義自己的頭文件,這些文件一般與c源程序放在同一目錄下呕臂,此時在# include中要用雙引號("")破托。

  1. 特殊符號,預(yù)編譯程序可以識別一些特殊的符號歧蒋。

例如在源程序中出現(xiàn)的LINE標(biāo)識將被解釋為當(dāng)前行號(十進(jìn)制數(shù))土砂,F(xiàn)ILE則被解釋為當(dāng)前被編譯的C源程序的名稱。預(yù)編譯程序?qū)τ谠谠闯绦蛑谐霈F(xiàn)的這些串將用合適的值進(jìn)行替換谜洽。

預(yù)編譯程序所完成的基本上是對源程序的“替代”工作萝映。經(jīng)過此種替代,生成一個沒有宏定義阐虚、沒有條件編譯指令序臂、沒有特殊符號的輸出文件。這個文件的含義同沒有經(jīng)過預(yù)處理的源文件是相同的实束,但內(nèi)容有所不同奥秆。下一步,此輸出文件將作為編譯程序的輸入而被翻譯成為機器指令咸灿。

編譯构订、優(yōu)化階段

經(jīng)過預(yù)編譯得到的輸出文件中,只有常量避矢;如數(shù)字悼瘾、字符串、變量的定義审胸,以及C語言的關(guān)鍵字亥宿,如main, if , else , for , while , { , } , + , - , * , \ 等等。

編譯程序所要作得工作就是通過詞法分析和語法分析砂沛,在確認(rèn)所有的指令都符合語法規(guī)則之后烫扼,將其翻譯成等價的中間代碼表示或匯編代碼。

優(yōu)化處理是編譯系統(tǒng)中一項比較艱深的技術(shù)尺上。它涉及到的問題不僅同編譯技術(shù)本身有關(guān)材蛛,而且同機器的硬件環(huán)境也有很大的關(guān)系圆到。優(yōu)化一部分是對中間代碼的優(yōu)化怎抛。這種優(yōu)化不依賴于具體的計算機。另一種優(yōu)化則主要針對目標(biāo)代碼的生成而進(jìn)行的芽淡。

對于前一種優(yōu)化马绝,主要的工作是刪除公共表達(dá)式、循環(huán)優(yōu)化(代碼外提挣菲、強度削弱富稻、變換循環(huán)控制條件掷邦、已知量的合并等)、復(fù)寫傳播椭赋,以及無用賦值的刪除抚岗,等等。

后一種類型的優(yōu)化同機器的硬件結(jié)構(gòu)密切相關(guān)哪怔,最主要的是考慮是如何充分利用機器的各個硬件寄存器存放有關(guān)變量的值宣蔚,以減少對于內(nèi)存的訪問次數(shù)。另外认境,如何根據(jù)機器硬件執(zhí)行指令的特點(如流水線胚委、RISC、CISC叉信、VLIW等)而對指令進(jìn)行一些調(diào)整使目標(biāo)代碼比較短亩冬,執(zhí)行的效率比較高,也是一個重要的研究課題硼身。

經(jīng)過優(yōu)化得到的匯編代碼必須經(jīng)過匯編程序的匯編轉(zhuǎn)換成相應(yīng)的機器指令硅急,方可能被機器執(zhí)行。

匯編

匯編過程實際上指把匯編語言代碼翻譯成目標(biāo)機器指令的過程鸠姨。對于被翻譯系統(tǒng)處理的每一個C語言源程序铜秆,都將最終經(jīng)過這一處理而得到相應(yīng)的目標(biāo)文件。目標(biāo)文件中所存放的也就是與源程序等效的目標(biāo)的機器語言代碼讶迁。

目標(biāo)文件由段組成连茧。通常一個目標(biāo)文件中至少有兩個段:

  1. 代碼段:該段中所包含的主要是程序的指令。該段一般是可讀和可執(zhí)行的巍糯,但一般卻不可寫啸驯。

  2. 數(shù)據(jù)段:主要存放程序中要用到的各種全局變量或靜態(tài)的數(shù)據(jù)。一般數(shù)據(jù)段都是可讀祟峦,可寫罚斗,可執(zhí)行的。

UNIX環(huán)境下主要有三種類型的目標(biāo)文件:

  1. 可重定位文件

其中包含有適合于其它目標(biāo)文件鏈接來創(chuàng)建一個可執(zhí)行的或者共享的目標(biāo)文件的代碼和數(shù)據(jù)宅楞。

  1. 共享的目標(biāo)文件

這種文件存放了適合于在兩種上下文里鏈接的代碼和數(shù)據(jù)针姿。

第一種是鏈接程序可把它與其它可重定位文件及共享的目標(biāo)文件一起處理來創(chuàng)建另一個目標(biāo)文件;

第二種是動態(tài)鏈接程序?qū)⑺c另一個可執(zhí)行文件及其它的共享目標(biāo)文件結(jié)合到一起厌衙,創(chuàng)建一個進(jìn)程映象距淫。

  1. 可執(zhí)行文件

它包含了一個可以被操作系統(tǒng)創(chuàng)建一個進(jìn)程來執(zhí)行之的文件。

匯編程序生成的實際上是第一種類型的目標(biāo)文件婶希。對于后兩種還需要其他的一些處理方能得到榕暇,這個就是鏈接程序的工作了。

2. 鏈接過程

由匯編程序生成的目標(biāo)文件并不能立即就被執(zhí)行,其中可能還有許多沒有解決的問題彤枢。

例如狰晚,某個源文件中的函數(shù)可能引用了另一個源文件中定義的某個符號(如變量或者函數(shù)調(diào)用等);在程序中可能調(diào)用了某個庫文件中的函數(shù)缴啡,等等壁晒。所有的這些問題,都需要經(jīng)鏈接程序的處理方能得以解決业栅。

鏈接程序的主要工作就是將有關(guān)的目標(biāo)文件彼此相連接讨衣,也即將在一個文件中引用的符號同該符號在另外一個文件中的定義連接起來,使得所有的這些目標(biāo)文件成為一個能夠被操作系統(tǒng)裝入執(zhí)行的統(tǒng)一整體式镐。

根據(jù)開發(fā)人員指定的同庫函數(shù)的鏈接方式的不同反镇,鏈接處理可分為兩種:

  1. 靜態(tài)鏈接

在這種鏈接方式下,函數(shù)的代碼將從其所在的靜態(tài)鏈接庫中被拷貝到最終的可執(zhí)行程序中娘汞。這樣該程序在被執(zhí)行時這些代碼將被裝入到該進(jìn)程的虛擬地址空間中歹茶。靜態(tài)鏈接庫實際上是一個目標(biāo)文件的集合,其中的每個文件含有庫中的一個或者一組相關(guān)函數(shù)的代碼你弦。

  1. 動態(tài)鏈接

在此種方式下惊豺,函數(shù)的代碼被放到稱作是動態(tài)鏈接庫或共享對象的某個目標(biāo)文件中。鏈接程序此時所作的只是在最終的可執(zhí)行程序中記錄下共享對象的名字以及其它少量的登記信息禽作。在此可執(zhí)行文件被執(zhí)行時尸昧,動態(tài)鏈接庫的全部內(nèi)容將被映射到運行時相應(yīng)進(jìn)程的虛地址空間。動態(tài)鏈接程序?qū)⒏鶕?jù)可執(zhí)行程序中記錄的信息找到相應(yīng)的函數(shù)代碼旷偿。

對于可執(zhí)行文件中的函數(shù)調(diào)用烹俗,可分別采用動態(tài)鏈接或靜態(tài)鏈接的方法。使用動態(tài)鏈接能夠使最終的可執(zhí)行文件比較短小萍程,并且當(dāng)共享對象被多個進(jìn)程使用時能節(jié)約一些內(nèi)存幢妄,因為在內(nèi)存中只需要保存一份此共享對象的代碼。但并不是使用動態(tài)鏈接就一定比使用靜態(tài)鏈接要優(yōu)越茫负。在某些情況下動態(tài)鏈接可能帶來一些性能上損害蕉鸳。

3. GCC的編譯鏈接

我們在linux使用的gcc編譯器便是把以上的幾個過程進(jìn)行捆綁,使用戶只使用一次命令就把編譯工作完成忍法,這的確方便了編譯工作潮尝,但對于初學(xué)者了解編譯過程就很不利了,下圖便是gcc代理的編譯過程:

從上圖可以看到:

  1. 預(yù)編譯

將.c 文件轉(zhuǎn)化成 .i文件

使用的gcc命令是:gcc –E

對應(yīng)于預(yù)處理命令cpp

  1. 編譯

將.c/.h文件轉(zhuǎn)換成.s文件

使用的gcc命令是:gcc –S

對應(yīng)于編譯命令 cc –S

  1. 匯編

將.s 文件轉(zhuǎn)化成 .o文件

使用的gcc 命令是:gcc –c

對應(yīng)于匯編命令是 as

  1. 鏈接

將.o文件轉(zhuǎn)化成可執(zhí)行程序

使用的gcc 命令是: gcc

對應(yīng)于鏈接命令是 ld

總結(jié)起來編譯過程就上面的四個過程:預(yù)編譯處理(.c) --> 編譯饿序、優(yōu)化程序(.s勉失、.asm)--> 匯編程序(.obj、.o嗤堰、.a戴质、.ko) --> 鏈接程序(.exe、.elf踢匣、.axf等)告匠。

4. 總結(jié)

C語言編譯的整個過程是非常復(fù)雜的,里面涉及到的編譯器知識离唬、硬件知識后专、工具鏈知識都是非常多的,深入了解整個編譯過程對工程師理解應(yīng)用程序的編寫是有很大幫助的输莺,希望大家可以多了解一些戚哎,在遇到問題時多思考、多實踐嫂用。

一般情況下型凳,我們只需要知道分成編譯和鏈接兩個階段,編譯階段將源程序(*.c) 轉(zhuǎn)換成為目標(biāo)代碼(一般是obj文件嘱函,至于具體過程就是上面說的那些階段)甘畅,鏈接階段是把源程序轉(zhuǎn)換成的目標(biāo)代碼(obj文件)與你程序里面調(diào)用的庫函數(shù)對應(yīng)的代碼連接起來形成對應(yīng)的可執(zhí)行文件(exe文件)就可以了,其他的都需要在實踐中多多體會才能有更深的理解往弓。


C/C++編譯過程

C/C++編譯過程主要分為4個過程
\color{blue}{1) 編譯預(yù)處理 }
\color{blue}{2) 編譯疏唾、優(yōu)化階段 }
\color{blue}{3) 匯編過程 }
\color{blue}{4) 鏈接程序}

\color{red}{一、編譯預(yù)處理}

(1)宏定義指令函似,如#define Name TokenString槐脏,#undef等。 對于前一個偽指令撇寞,預(yù)編譯所要做的是將程序中的所有Name用TokenString替換顿天,

但作為字符串常量的 Name則不被替換。對于后者蔑担,則將取消對某個宏的定義露氮,使以后該串的出現(xiàn)不再被替換。

(2)條件編譯指令钟沛,如#ifdef畔规,#ifndef,#else恨统,#elif叁扫,#endif等。 這些偽指令的引入使得程序員可以通過定義不同的宏來決定編譯程序?qū)δ男┐a進(jìn)行處理畜埋。

預(yù)編譯程序?qū)⒏鶕?jù)有關(guān)的文件莫绣,將那些不必要的代碼過濾掉

(3) 頭文件包含指令,如#include "FileName"或者#include <FileName>等悠鞍。 在頭文件中一般用偽指令#define定義了大量的宏(最常見的是字符常量)对室,

同時包含有各種外部符號的聲明。 包含到c源程序中的頭文件可以是系統(tǒng)提供的,這些頭文件一般被放在/usr/include目錄下掩宜。

在程序中#include它們要使用尖括號(< >)蔫骂。

另外開發(fā)人員也可以定義自己的頭文件,這些文件一般與c源程序放在同一目錄下牺汤,此時在#include中要用雙引號("")辽旋。

(4)特殊符號,預(yù)編譯程序可以識別一些特殊的符號檐迟。 例如在源程序中出現(xiàn)的#line標(biāo)識將被解釋為當(dāng)前行號(十進(jìn)制數(shù))补胚,
上面程序?qū)崿F(xiàn)了對宏line的運用

(5)預(yù)處理模塊 預(yù)處理工作由#pragma命令完成,#Pragma命令將設(shè)定編譯器的狀態(tài)或者是指示編譯器完成一些特定的動作追迟。

#pragma指令對每個編譯器給出了一個方法,在保持與C和C++語言完全兼容的情況下,給出主機或操作系統(tǒng)專有的特征溶其。

依據(jù)定義,編譯指示是機器或操作系統(tǒng)專有的,且對于每個編譯器都是不同的。
打開C標(biāo)準(zhǔn)庫函數(shù)敦间,如stdio.h握联,我們總能找到下面這一句指示編譯器初始化堆棧

#include "iostream"
#line 100
using namespace std;
int main(int argc, char* argv[])
{
cout<<"__LINE__:"<<__LINE__<<endl;
return 0;
}

/*--------------------

  • 輸出結(jié)果為:
  • LINE:103
  • 本來輸出的結(jié)果應(yīng)該是 7,但是用#line指定行號之后金闽,使下一行的行號變?yōu)?
  • 到輸出語句恰為行103
    ---------------------/
    C/C++編譯過程
    或者程序指示編譯器去鏈接系統(tǒng)動態(tài)鏈接庫或用戶自定義鏈接庫
    \color{red}{二、編譯剿骨、優(yōu)化階段}
    經(jīng)過預(yù)編譯得到的輸出文件中代芜,只有常量;如數(shù)字浓利、字符串挤庇、變量的定義群井,以及C語言的關(guān)鍵字逐虚,如main,if,else,for,while,{,}, +,-,
    ,\等等。
    在《編譯原理》中我們可以了解到一個編譯器對程序代碼的編譯主要分為下面幾個過程:
    \color{blue}{a) 詞法分析 }
    \color{blue}{b) 語法分析 }
    \color{blue}{c) 語義分析 }
    \color{blue}{d) 中間代碼生成 }
    \color{blue}{e) 代碼優(yōu)化 }
    \color{blue}{f) 代碼生成 }
    \color{blue}{g) 符號表管理 }
    \color{blue}{h) 將多個步驟組合成趟 }
    \color{blue}{i) 編譯器構(gòu)造工具 }
    在這里我們主要強調(diào)對函數(shù)壓棧方式(函數(shù)調(diào)用約定)的編譯處理
    C與C++語言調(diào)用方式大體相同枯冈,下面是幾種常用的調(diào)用方式:
    __cdecl 是C DECLaration的縮寫(declaration苹威,聲明)昆咽,表示C語言默認(rèn)的函數(shù)調(diào)用方法:所有參數(shù)從右到左依次入棧,

這些參數(shù)由調(diào)用者清除牙甫,稱為手動清棧掷酗。被調(diào)用函數(shù)不需要求調(diào)用者傳遞多少參數(shù),調(diào)用者傳遞過多或者過少的參數(shù)窟哺,

甚至完全不同的參數(shù)都不會產(chǎn)生編譯階段的錯誤泻轰。

_stdcall 是StandardCall的縮寫,是C++的標(biāo)準(zhǔn)調(diào)用方式:所有參數(shù)從右到左依次入棧且轨,如果是調(diào)用類成員的話浮声,

最后一個入棧的是this指針虚婿。這些堆棧中的參數(shù)由被調(diào)用的函數(shù)在返回后清除,使用的指令是 retnX泳挥,X表示參數(shù)占用的字節(jié)數(shù)然痊,

CPU在ret之后自動彈出X個字節(jié)的堆棧空間羡洁。稱為自動清棧。函數(shù)在編譯的時候就必須確定參數(shù)個數(shù)爽丹,

并且調(diào)用者必須嚴(yán)格的控制參數(shù)的生成筑煮,不能多,不能少粤蝎,否則返回后會出錯真仲。

PASCAL 是Pascal語言的函數(shù)調(diào)用方式,在早期的c/c++語言中使用這種調(diào)用方式初澎,

參數(shù)壓棧順序與前兩者相反秸应,但現(xiàn)在我們在程序中見到的都是它的演化版本,其實

#pragma comment(lib,_T("GDI32.lib"))
#ifdef _MSC_VER
/*
* Currently, all MS C compilers for Win32 platforms default to 8 byte
* alignment.
*/
#pragma pack(push,_CRT_PACKING)
#endif /* _MSC_VER */

C/C++編譯過程
質(zhì)是另一種調(diào)用方式
_fastcall是編譯器指定的快速調(diào)用方式碑宴。由于大多數(shù)的函數(shù)參數(shù)個數(shù)很少软啼,使用堆棧傳遞比較費時。因此_fastcall通常規(guī)定將前兩個(或若干個)參數(shù)由寄存器傳遞延柠,其余參數(shù)還是通過堆棧傳遞祸挪。不同編譯器編譯的程序規(guī)定的寄存器不同。返回方式和_stdcall相當(dāng)贞间。
_thiscall 是為了解決類成員調(diào)用中this指針傳遞而規(guī)定的贿条。_thiscall要求把this指針放在特定寄存器中,該寄存器由編譯器決定增热。VC使用ecx整以,Borland的C++編譯器使用eax。返回方式和_stdcall相當(dāng)峻仇。
_fastcall 和 _thiscall涉及的寄存器由編譯器決定公黑,因此不能用作跨編譯器的接口。所以Windows上的COM對象接口都定義為_stdcall調(diào)用方式摄咆。
C中不加說明默認(rèn)函數(shù)為_cdecl方式(C中也只能用這種方式)帆调,C++也一樣,但是默認(rèn)的調(diào)用方式可以在IDE環(huán)境中設(shè)置豆同。簡單的我們可以從printf函數(shù)看出
printf使用從從左至右壓棧番刊,返回int型并由_CRTIMP指定封在動態(tài)鏈接庫中。
通過金典的hello world程序我們可以知道編譯器對其argc和argv[]這兩個參數(shù)進(jìn)行了壓棧影锈,并且argc留在了棧頂
優(yōu)化處理是編譯系統(tǒng)中一項比較艱深的技術(shù)芹务。它涉及到的問題不僅同編譯技術(shù)本身有關(guān)蝉绷,而且同機器的硬件環(huán)境也有很大的關(guān)系。優(yōu)化處理主要分為下面幾個過程:

  1. 局部優(yōu)化
    \color{blue}{a) 基本塊的劃分 }
    \color{blue}{b) 基本塊的變換 }
    \color{blue}{c) 基本塊的DAG表示 }
    \color{blue}{d) DAG的應(yīng)用 }
    \color{blue}{e) 構(gòu)造算法討論 }

  2. 控制流分析和循環(huán)優(yōu)化
    \color{blue}{a) 程序流圖與循環(huán) }

/*金典的hello world*/
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("hello world");
return 0;
}
_Check_return_opt_ _CRTIMP int __cdecl printf(_In_z_ _Printf_format_string_ const char * _Format, ...);
#define CALLBACK _stdcall /* Windows程序回調(diào)函數(shù)*/
#define WINAPI _stdcall
#define WINAPIV _cdecl
#define PASCAL _stdcall /*在c++語言中使用了StandardCall調(diào)用方式*/
#define PASCAL _cdecl/*在c語言中使用了C DECLaration調(diào)用方式*/

C/C++編譯過程
\color{blue}{b) 循環(huán) }
\color{blue}{c) 循環(huán)的查找 }
\color{blue}{d) 可歸約流圖 }
\color{blue}{e) 循環(huán)優(yōu)化 }

  1. 數(shù)據(jù)流的分析與全局優(yōu)化
    \color{blue}{a) 一些主要的概念 }
    \color{blue}{b) 數(shù)據(jù)流方程的一般形式 }
    \color{blue}{c) 到達(dá)一定值數(shù)據(jù)流方程 }
    \color{blue}{d) 可用表達(dá)式及其數(shù)據(jù)流方程 }
    \color{blue}{e) 活躍變量數(shù)據(jù)流方程 }
    \color{blue}{f) 復(fù)寫傳播 }
    經(jīng)過優(yōu)化得到的匯編代碼必須經(jīng)過匯編程序的匯編轉(zhuǎn)換成相應(yīng)的機器指令枣抱,方可能被機器執(zhí)行熔吗。
    \color{red}{三、匯編過程}

匯編過程實際上指把匯編語言代碼翻譯成目標(biāo)機器指令的過程佳晶。對于被翻譯系統(tǒng)處理的每一個C語言源程序桅狠,

都將最終經(jīng)過這一處理而得到相應(yīng)的目標(biāo)文件。目標(biāo)文件中所存放的也就是與源程序等效的目標(biāo)的機器語言代碼轿秧。

目標(biāo)文件由段組成中跌。通常一個目標(biāo)文件中至少有兩個段: 代碼段:該段中所包含的主要是程序的指令。

該段一般是可讀和可執(zhí)行的菇篡,但一般卻不可寫漩符。 數(shù)據(jù)段:主要存放程序中要用到的各種全局變量或靜態(tài)的數(shù)據(jù)。一般數(shù)據(jù)段都是可讀驱还,可寫嗜暴,可執(zhí)行的。

\color{red}{四议蟆、鏈接程序}

由匯編程序生成的目標(biāo)文件并不能立即就被執(zhí)行闷沥,其中可能還有許多沒有解決的問題。

例如咐容,某個源文件中的函數(shù)可能引用了另一個源文件中定義的某個符號(如變量或者函數(shù)調(diào)用等)狐赡;

在程序中可能調(diào)用了某個庫文件中的函數(shù),等等疟丙。所有的這些問題颖侄,都需要經(jīng)鏈接程序的處理方能得以解決。

鏈接程序的主要工作就是將有關(guān)的目標(biāo)文件彼此相連接享郊,也即將在一個文件中引用的符號同該符號在另外一個文件中的定義連接起來览祖,

使得所有的這些目標(biāo)文件成為一個能夠誒操作系統(tǒng)裝入執(zhí)行的統(tǒng)一整體。

根據(jù)開發(fā)人員指定的同庫函數(shù)的鏈接方式的不同炊琉,鏈接處理可分為兩種:

(1)靜態(tài)鏈接 在這種鏈接方式下展蒂,函數(shù)的代碼將從其所在地靜態(tài)鏈接庫中被拷貝到最終的可執(zhí)行程序中。

這樣該程序在被執(zhí)行時這些代碼將被裝入到該進(jìn)程的虛擬地址空間中苔咪。靜態(tài)鏈接庫實際上是一個目標(biāo)文件的集合锰悼,

其中的每個文件含有庫中的一個或者一組相關(guān)函數(shù)的代碼。

(2) 動態(tài)鏈接
在此種方式下团赏,函數(shù)的代碼被放到稱作是動態(tài)鏈接庫或共享對象的某個目標(biāo)文件中箕般。鏈接程序此時所作的只是在最終的可執(zhí)行程序中記錄下共享對象的名字以及其它少量的登記信息。在此可執(zhí)行文件被執(zhí)行時舔清,動態(tài)鏈接庫的全部內(nèi)容將被映射到運行時相應(yīng)進(jìn)程的虛地址空間丝里。動態(tài)鏈接程序?qū)⒏鶕?jù)可執(zhí)行程序中記錄的信息找到相應(yīng)的函數(shù)代碼曲初。C/C++編譯過程對于可執(zhí)行文件中的函數(shù)調(diào)用,可分別采用動態(tài)鏈接或靜態(tài)鏈接的方法杯聚。使用動態(tài)鏈接能夠使最終的可執(zhí)行文件比較短小臼婆,并且當(dāng)共享對象被多個進(jìn)程使用時能節(jié)約一些內(nèi)存,因為在內(nèi)存中只需要保存一份此共享對象的代碼幌绍。但并不是使用動態(tài)鏈接就一定比使用靜態(tài)鏈接要優(yōu)越颁褂。在某些情況下動態(tài)鏈接可能帶來一些性能上損害。

----------------------------------------------------作者 張彥升

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末傀广,一起剝皮案震驚了整個濱河市颁独,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌主儡,老刑警劉巖奖唯,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惨缆,死亡現(xiàn)場離奇詭異糜值,居然都是意外死亡,警方通過查閱死者的電腦和手機坯墨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門寂汇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人捣染,你說我怎么就攤上這事骄瓣。” “怎么了耍攘?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵榕栏,是天一觀的道長。 經(jīng)常有香客問我蕾各,道長扒磁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任式曲,我火速辦了婚禮妨托,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吝羞。我一直安慰自己兰伤,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布钧排。 她就那樣靜靜地躺著敦腔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪恨溜。 梳的紋絲不亂的頭發(fā)上会烙,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天负懦,我揣著相機與錄音,去河邊找鬼柏腻。 笑死纸厉,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的五嫂。 我是一名探鬼主播颗品,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼沃缘!你這毒婦竟也來了躯枢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤槐臀,失蹤者是張志新(化名)和其女友劉穎锄蹂,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體水慨,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡得糜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了晰洒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片朝抖。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖谍珊,靈堂內(nèi)的尸體忽然破棺而出治宣,到底是詐尸還是另有隱情,我是刑警寧澤砌滞,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布侮邀,位于F島的核電站,受9級特大地震影響贝润,放射性物質(zhì)發(fā)生泄漏绊茧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一题暖、第九天 我趴在偏房一處隱蔽的房頂上張望按傅。 院中可真熱鬧,春花似錦胧卤、人聲如沸唯绍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽况芒。三九已至,卻和暖如春叶撒,著一層夾襖步出監(jiān)牢的瞬間绝骚,已是汗流浹背耐版。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留压汪,地道東北人粪牲。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像止剖,于是被迫代替她去往敵國和親腺阳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 一穿香、溫故而知新 1. 內(nèi)存不夠怎么辦 內(nèi)存簡單分配策略的問題地址空間不隔離內(nèi)存使用效率低程序運行的地址不確定 關(guān)于...
    SeanCST閱讀 7,808評論 0 27
  • 原文地址:C語言函數(shù)調(diào)用棧(一)C語言函數(shù)調(diào)用棧(二) 0 引言 程序的執(zhí)行過程可看作連續(xù)的函數(shù)調(diào)用亭引。當(dāng)一個函數(shù)執(zhí)...
    小豬啊嗚閱讀 4,610評論 1 19
  • 學(xué)過C語言的人都應(yīng)該知道,我們所編輯的C語言程序是不能直接放到機器上運行的皮获,它只不過是一個帶".c"后綴的文件(也...
    KBAC閱讀 4,848評論 0 1
  • 計算機系統(tǒng)漫游 代碼從文本到可執(zhí)行文件的過程(c語言示例):預(yù)處理階段焙蚓,處理 #inlcude , #defin...
    willdimagine閱讀 3,584評論 0 5
  • 水110克洒宝,雞蛋一個购公,酵母4克,糖10克待德,先攪拌君丁,放高粉250克枫夺,鹽2克将宪,揉面3分鐘,加黃油15克繼續(xù)揉面3分鐘橡庞,...
    清凌凌的遂閱讀 247評論 0 0