1. 程式人生 > >C++ 編譯,執行過程 詳解。

C++ 編譯,執行過程 詳解。

        要更深入瞭解C++, 必須要知道一個程式從開始到結束都幹了些什麼, 怎麼幹的。 所以我從C++編譯到執行過程,解析下程式是怎麼跑的。

        首先,初略的說一下之前C++的編譯過程,C++編譯過程包括預編譯-》彙編-》編譯-》連結。稱為一個可執行檔案。(Windows平臺下為.exe檔案)。

預編譯主要展開包含的標頭檔案,巨集定義等操作。例如一個簡單的main程式,編譯預編譯後,的檔案對比。

  可以看到裡面的巨集已經被去掉了。如果定了那個巨集,那麼巨集裡面的內容也會顯示出來。標頭檔案也是,如果你包含了你一個.h 檔案,那麼整個.h檔案會包含進來。

     彙編過程,就是把已經預編譯的檔案編譯成彙編程式碼的過程,整個過程會包含語法,詞法的分析,和一些優化操作。

     編譯過程其實是跟彙編可以合成一個階段,變成目的碼。也就是二進位制檔案。

     連結過程是將單個編譯後的檔案連結成一個可執行程式。前面的預編譯、彙編、編譯都是正對單個檔案,以一個檔案為一個編譯單元,而連結則是將所有關聯到的編譯後單元檔案和應用的到庫檔案,進行一次連結處理,之前編譯過的檔案 如果有用到其他檔案裡面定義到的函式,全域性變數,在這個過程中都會進行解析。

首先看看編譯後的檔案樣子(已VS2012編譯後的OBJ檔案為例子,不同編譯器 樣式可能會不同。)

編譯前的檔案

#include "Car.h"
int main(int argc, char* argv[])
{
 Car* p = new Car();

 delete p;
 return 1;
}

編譯後的樣子(由於編譯後的檔案 資訊太多 只貼出裡面未解析符號部分。)

 UNDEF:00002DC4 ; int __thiscall Car::Car(Car *__hidden this)
UNDEF:00002DC4                 extrn [email protected]@[email protected]:near ; CODE XREF: _main+63p
UNDEF:00002DC8 ; int __thiscall Car::~Car(Car *__hidden this)
UNDEF:00002DC8                 extrn

[email protected]@[email protected]:near
UNDEF:00002DC8                                         ; CODE XREF: Car::`scalar deleting destructor'(uint)+26p
UNDEF:00002DCC ; __fastcall _RTC_CheckStackVars(x, x)
UNDEF:00002DCC                 extrn @[email protected]:near
UNDEF:00002DCC                                         ; CODE XREF: std::_String_alloc<0,std::_String_base_types<char,std::allocator<char>>>::_Alloc_proxy(void)+68p
UNDEF:00002DCC                                         ; $LN19+72p ...
UNDEF:00002DD0 ; __fastcall __security_check_cookie(x)
UNDEF:00002DD0                 extrn @[email protected]:near
UNDEF:00002DD0                                         ; CODE XREF: [email protected]@[email protected]@[email protected]@[email protected]+Fp
UNDEF:00002DD0                                         ; [email protected][email protected]@@[email protected]@[email protected][email protected]@@@[email protected]@[email protected]@[email protected]@Z+Fp ...
UNDEF:00002DD4 ; __stdcall _CxxThrowException(x, x)

編譯後的檔案用(用反彙編成彙編程式碼檢視) 其中實現函式會變成一堆彙編指令。而那些引用到的在其他檔案裡面實現的函式將會變成一個特點的符號(如上面中的呼叫Car類的建構函式 extrn [email protected]@[email protected]:near)這些符號稱做為解析的符號,表示在連結的時候需要被解析。符號的生成名稱具體跟編譯器有關,但是會保證一個類的某個函式名稱在同一個編譯裡面必須是唯一的,因為我們在預編譯階段已經把Car.h包含進來所以編譯器能正確生成這個函式的名字,然後在連結的時候 會找到改名字的函式,把此標識名字替換為函式的地址。這樣就實現的連結。

在符號解析(symbol resolution)階段,連結器按照所有目標檔案和庫檔案出現在命令列中的順序從左至右依次掃描它們,在此期間它要維護若干個集合:(1)集合E是將被合併到一起組成可執行檔案的所有目標檔案集合;(2)集合U是未解析符號(unresolved symbols,比如已經被引用但是還未被定義的符號)的集合;(3)集合D是所有之前已被加入到E的目標檔案定義的符號集合。一開始,E、U、D都是空的。

(1): 對命令列中的每一個輸入檔案f,連結器確定它是目標檔案還是庫檔案,如果它是目標檔案,就把f加入到E,並把f中未解析的符號和已定義的符號分別加入到U、D集合中,然後處理下一個輸入檔案。

(2): 如果f是一個庫檔案,連結器會嘗試把U中的所有未解析符號與f中各目標模組定義的符號進行匹配。如果某個目標模組m定義了一個U中的未解析符號,那麼就把 m加入到E中,並把m中未解析的符號和已定義的符號分別加入到U、D集合中。不斷地對f中的所有目標模組重複這個過程直至到達一個不動點(fixed point),此時U和D不再變化。而那些未加入到E中的f裡的目標模組就被簡單地丟棄,連結器繼續處理下一輸入檔案。

(3): 如果處理過程中往D加入一個已存在的符號,或者當掃描完所有輸入檔案時U非空,連結器報錯並停止動作。否則,它把E中的所有目標檔案合併在一起生成可執行檔案。



相關推薦

C++ 編譯執行過程

        要更深入瞭解C++, 必須要知道一個程式從開始到結束都幹了些什麼, 怎麼幹的。 所以我從C++編譯到執行過程,解析下程式是怎麼跑的。         首先,初略的說一下之前C++的編譯過程,C++編譯過程包括預編譯-》彙編-》編譯-》連結。稱為一個可執行檔案

C++ 編譯執行過程 具體解釋

string -m span font ont 程序 fas 全局 內容 要更深入了解C++, 必需要知道一個程序從開始到結束都幹了些什麽, 怎麽幹的。 所以我從C++編譯到執行過程,解析下程序是怎麽跑的。

C/C++編譯和連結過程 (重定向表匯出符號表未解決符號表)

詳解link  有 些人寫C/C++(以下假定為C++)程式,對unresolved external link或者duplicated external simbol的錯誤資訊不知所措(因為這樣的錯誤資訊不能定位到某一行)。或者對語言的一些部分不知道為什麼要(或者不要)這樣那樣設計。瞭解本文之後, 或許會有

gcc 的執行過程 預處理 編譯 彙編 連結

在Linux中,使用GCC編譯程式的過程可以被分為四個階段: 下面我們以hello.c為例,來看看各個階段,編譯器做了什麼 ----對hello.c進行預編譯 執行命令:gcc -E hello.c -o hello.i,開啟生成的hello.i檔案

SQL語句執行過程

使用 錯誤信息 意思 排錯 表達 對象 data 才會 結果集   一、SQL語句執行原 第一步:客戶端把語句發給服務器端執行當我們在客戶端執行 select 語句時,客戶端會把這條 SQL 語句發送給服務器端,讓服務器端的進程來處理這語句。也就是說,Oracl

計算機指令執行過程

一、計算機的基本組成 馮·諾依曼計算機的特點(機器以運算器為中心) 1. 計算機由控制器(分析和執行機器指令並控制各部件的協同工作)、運算器(根據控制訊號對資料進行算術運算和邏輯運算)、儲存器(記憶體儲存中間結果,外存儲存需要長期儲存的資訊)、輸入裝置(接收外界資訊)和輸出裝置(向外界輸送資

Java編譯程式和執行過程

java整個編譯以及執行的過程相當繁瑣,我就舉一個簡單的例子說明: 編譯原理簡單過程:詞法分析 --> 語法分析 --> 語義分析和中間程式碼生成 --> 優化 --> 目的碼生成 Java程式從原始檔建立到程式執行要經過兩大步驟: 1、Java檔案會由

大資料基礎課之Hadoop MapReduce執行過程

述一下mapreduce的流程(shuffle的sort,partitions,group) 首先是 Mapreduce經過SplitInput 輸入分片 決定map的個數在用Record記錄 key value。然後分為以下三個流程: Map: 輸入 key

Spark MLlib 貝葉斯分類演算法例項具體程式碼及執行過程

import org.apache.log4j.{Level, Logger} import org.apache.spark.{SparkConf, SparkContext} import org.apache.spark.mllib.classification.{NaiveBayes, Naiv

MapReduce On yarn執行過程

老的MapReduce主要包括Job Tracker和Task Tracker,YARN中主要是三個元件:Resource Manager、Node Manager和Application Master。Resource Manager負責全域性資源分配,Applicatio

給sublime3配置C++(編譯執行和格式化程式碼)

這段時間一直在搞Sbulime,以前一直都是用Codeblocks,但是sublime更加輕便 下載安裝sublime什麼的我就不說了,先講怎麼配置MinGW 安裝好MinGW後,需要修改環境變數,右鍵我的電腦->屬性->高階系統設定->高階->環境

C語言檔案操作

在 C 語言中,檔案操作的函式大多包含在 標頭檔案中,使用時記得 #include。 一、開啟和關閉檔案 1. 開啟檔案 FILE * fopen ( const char * filename, const char * mode ); 開啟一個檔案,成功則返回

非相關子查詢和相關子查詢執行過程

前段時間有一個相關子查詢的SQL語句,看不太懂他是如何執行的,為什麼會出現那個結果。著實糾結了一把。下面來講一下非相關子查詢和相關子查詢的執行過程是怎樣的。 非相關子查詢 先看一個非相關子查詢到sql

Hibernate 初相識(一)Hibernate API 配置檔案對映檔案

導航{ } Hibernate 在三層框架中的位置。 一,第一個Hibernate 專案。  地址:https://github.com/gengzi/Hibernate 【1】匯入jar包 解

GCC編譯系統基本過程

GCC編譯驅動程式,將源程式hello.c翻譯為一個可執行目標檔案hello過程,分為四個階段; 下面是我總結的思維導圖,比純文字的好理解一點。   第一階段,預處理階段;前處理器(cpp)根據以

Spark計算Pi執行過程---Spark學習筆記4

上回運行了一個計算Pi的例子 那麼Spark究竟是怎麼執行的呢? 我們來看一下指令碼 #!/bin/sh export YARN_CONF_DIR=/home/victor/software/hadoop-2.2.0/etc/hadoop SPARK_JAR=./ass

Hadoop MapReduce執行過程(帶hadoop例子)

問題導讀1.MapReduce是如何執行任務的? 2.Mapper任務是怎樣的一個過程? 3.Reduce是如何執行任務的? 4.鍵值對是如何編號的? 5.例項,如何計算沒見最高氣溫? 分析MapReduce執行過程    MapReduce執行的時候,會通過Mapper執

mysql中SQL執行過程

 mysql執行一個查詢的過程,到底做了些什麼:   客戶端傳送一條查詢給伺服器; 伺服器先

c++11多執行(一)

  原文作者:aircraft 原文連結:https://www.cnblogs.com/DOMLX/p/10914162.html              最近是恰好寫了一些c++11多執行緒有關的東西,就寫一下筆記留著以後自己忘記回來看吧,也不是專門寫給讀者看的,我就想到哪就寫到哪吧 &nbs

Java連載3-編譯執行階段&JRE,JDK,JVM關係

·一、 1.JDK下載地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk12-downloads-5295953.html 二、Java的載入與執行 1.Java程式執行包括: (1)編譯階段:檢查Java源程式是否符合Java語法,