1. 程式人生 > >C程式的編譯連結過程

C程式的編譯連結過程

程式由原始檔編譯得到可執行檔案看起來好像是很簡單的過程,windows的IDE環境下,點一下bulid就可以生成可執行檔案,在Linux環境下,gcc編譯器也提供了很多選項可以很方便的從原始檔生成可執行檔案。事實上程式的編譯和連結是一個非常複雜的過程,IDE幫我們隱藏了大量的細節。下面我們以最經典的hello,world程式來分析一下,從源程式到生成可執行檔案都發生了哪些事情。

//main.c檔案內容
#include<stdio.h>
int main()
{
printf(“hello,world.\n”);
return 0;
}

##1. 預處理
預處理的主要作用有三個:

  1. 處理原始檔程式碼中以”#”開頭的那些程式碼,比如#include,#define等。將所有的巨集定義全部展開。
  2. 處理條件編譯
  3. 刪除所有註釋

通過gcc的-E選項來預處理main.c檔案。
gcc –E main.c –o main.i

這裡寫圖片描述

檢視一下生成的main.i的檔案內容,可以看到stdio.h檔案內的內容已經全部被插入到檔案當中了,同時所有的巨集定義也被展開(main.i檔案很長,擷取的是一部分)。在檔案的最後是我們main函式的程式碼。

#2. 編譯
編譯就是將預處理得到的*.i檔案生成彙編程式碼檔案(.s檔案)。注意:通常所說的編譯是指程式從原始碼到生成可執行檔案的全過程,在這裡指的由.i檔案生成*.s檔案的過程。輸入下面的命令來實現編譯過程,得到main.s檔案。
gcc –S main.i –o main.s


main.s檔案全部內容如下:
這裡寫圖片描述

#3. 彙編
彙編就是將彙編程式碼變成機器碼。每一條彙編語句幾乎都對應了一條機器碼。所以這一步驟非常簡單,根據彙編指令和機器指令對照表一對一翻譯就OK。輸入下面的指令實現這一過程。
gcc –c main.s –o main.o
此時,main.o檔案已經生成,這個時候main.o已經是一個二進位制檔案,不能用cat檢視,用hexdump來看一下main.o檔案內容。
這裡寫圖片描述

可以看到main.o檔案全部都是數字。不過main.o檔案還是不能執行,因為還沒有把庫連線進來。
#4. 連結
連結就是將庫檔案連結到程式,庫檔案分為兩種,一種是靜態庫(也成為存檔檔案),一種是動態庫(也稱為共享庫)。關於靜態庫和動態庫,請參考上一篇博文。
使用以下指令完成連結過程
gcc main.s –o main.out


生成main.out可執行檔案。

以上就是從原始檔到可執行檔案的全部過程。這是一個很簡單的範例,在main.c檔案中僅包含了標準標頭檔案,沒有包含自定義的標頭檔案。下面介紹一個簡單的例子。
首先準備三個檔案

//main.c檔案內容
#include<stdio.h>
#include "fun.h"
int main()
{
    printf("the answer is %d\n",calc(5,6));
    printf("hello,world.\n");
    return 0;   
}
//fun.h檔案內容
#ifndef FUN_H
#define FUN_H
int calc(int a,int b);
#endif
//fun.c檔案內容
#include"fun.h"
int calc(int a,int b)
{
    return a+b;
}

在main.c檔案中包含了fun.h檔案,並呼叫了fun.h中定義的calc函式,calc函式的實現在calc.c檔案中。
#1.預處理、編譯、彙編main.c檔案
gcc -c main.c -o main.o
這裡寫圖片描述
此時main.o檔案是不能生成可執行檔案的。
這裡寫圖片描述
編譯器提示undefined reference to `calc’,因為我們沒有連結庫檔案。
#2.建立靜態庫檔案
1.首先,編譯fun.c得到fun.o目標檔案
gcc -c fun.c
這裡寫圖片描述
2.然後,建立靜態庫檔案
ar crv libfun.a fun.o
這裡寫圖片描述
3.在某些系統中,還要為靜態庫生成一個內容表
ranlib libfun.a
4.庫檔案建立完成後,就可以連結了。
#3.程式連結靜態庫檔案
前面已經生成了main.o文和libfun.a檔案,現在我們連結一下,生成可執行檔案。
gcc main.o -o main.out -L. -l fun
注意一下這條語句的規則,-L表示指定庫檔案目錄,”.”表示當前資料夾,這裡也可以寫出目錄完整路徑。-l fun表示指定庫檔名,庫檔案的完整名是libfun.a,前面的lib和字尾.a均省略。
這裡寫圖片描述
可見,main.out檔案已經生成,可以執行
這裡寫圖片描述

相關推薦

C程式編譯連結】gcc使用命令介紹 gcc的使用簡介與命令列引數說明

1.gcc或者g++安裝rpm -qa|grep gcc ==>檢查gcc是否安裝gcc -v ==>檢查gcc版本 編譯器會在可執行檔案中植入一些資訊,可執行檔案會變大。一般開發時候使用 -g ,編譯一個 “release 版本” 時不使用 -g 編譯。gcc如果是最新的則不重

C程式編譯連結】gcc使用命令介紹 GCC編譯器編譯連結  

1.gcc安裝 rpm -qa|grep gcc ==>檢查gcc是否安裝 gcc -v ==>檢查gcc版本 yum -y install gcc ==>安裝gcc  2.基本語法 gcc最基本的用法是:gcc [options]

c語言編譯連結過程

學過C語言的人都應該知道,我們所編輯的C語言程式是不能直接放到機器上執行的,它只不過是一個帶”.c”字尾的檔案(也稱為原始碼)而已,需要經過一定的處理才能轉換成機器上可執行的可執行檔案。我們將對C語言的這種處理過程稱為編譯與連結。 編譯就是把文字形式原始碼翻譯

程序虛擬地址空間 程式編譯連結過程

1..程式編譯、連結、執行的過程。 (1)預編譯階段**** 生成*.i檔案。 處理原始碼檔案,即以“#”開始的預編譯指令。 有展開巨集;去註釋;新增行號;保留所有#pragma編譯指令。

C/C++程式編譯連結過程

在以前學習C語言的時候,想必大家寫的第一個程式碼都是“hello world”吧。在以前我們除錯一個程式碼的時候是在vc++6.0或者是在vs上面除錯的,這種就是整合開發環境,它為我們簡化了一個程式碼的

C程式編譯連結過程

程式由原始檔編譯得到可執行檔案看起來好像是很簡單的過程,windows的IDE環境下,點一下bulid就可以生成可執行檔案,在Linux環境下,gcc編譯器也提供了很多選項可以很方便的從原始檔生成可執行檔案。事實上程式的編譯和連結是一個非常複雜的過程,IDE幫我

C/C++ 程式編譯連結過程詳解(靜態連結

我們知道一個程式的執行需要經過編譯和連結兩個階段,其過程究竟是怎樣的呢? 程式的編譯階段分為以下幾個步驟,分別是預編譯、編譯、彙編、生成二進位制可重定向檔案(.o)。 預編譯: 首先是原始碼檔案xxx.c和相關的標頭檔案被預編譯器編譯成一個.i檔案。

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

C語言的編譯連結過程要把我們編寫的一個c程式(原始碼)轉換成可以在硬體上執行的程式(可執行程式碼),需要進行編譯和連結。編譯就是把文字形式原始碼翻譯為機器語言形式的目標檔案的過程。連結是把目標檔案、作業系統的啟動程式碼和用到的庫檔案進行組織,形成最終生成可執行程式碼的過程。過程圖解如下: 從圖上可以看到,

make,makefile和程式編譯連結過程

一,Linux下程式執行過程 1,在一個目錄下新建三個檔案:main.c hello.c hello.h分別編寫他們如下圖: 2,想要讓這個程式執行起來,就必須對上面的三個檔案分別進行編譯連結執行,如下圖: 通過上面這個過程。我們可

C&C++編譯連結過程

本文講解編譯連結過程,因為才疏學淺可能有些不準確。 使用c檔案的編譯連結過程,使用Linux系統用來檢視檔案資訊。 (1)從原始檔main.c編譯連結成main.exe,需要經歷如下步驟:     (2)其中符號和符號表是什麼呢?段又是什麼? 段:在一個程

C語言的編譯連結過程的介紹

C語言的編譯連結過程要把我們編寫的一個c程式(原始碼)轉換成可以在硬體上執行的程式(可執行程式碼),需要進行編譯和連結。編譯就是把文字形式原始碼翻譯為機器語言形式的目標檔案的過程。連結是把目標檔案、作業系統的啟動程式碼和用到的庫檔案進行組織形成最終生成可執行程式碼的過程。

程式編譯連結過程

原文連結: https://www.cnblogs.com/kekec/p/3238741.html還是從HelloWorld開始說吧...#include <stdio.h> int main(int argc, char* argv[]) { pri

C++程式編譯過程詳解

C++程式編譯過程 一般來說,我們可以把C++程式編譯過程分為以下三步 編譯預處理 主要進行原始碼級別上的操作,前處理器執行原始碼中的預處理命令(以‘#’號開頭的語句),其中預處理命令可以分為以下幾類 a. 巨集定義命令[ #define 巨集名 替換內容 、#undef

C語言編譯連結載入過程

連結: 可執行程式是由各個目標檔案經過連線而成。其主體部分依然是程式碼段、只讀資料段和讀寫資料段,這三個段由各個目標檔案(.o)經過“組合”而成。C語言目標檔案到可執行程式的連線如下圖所示。 載入:載入器把可執行檔案從外存載入到記憶體並進行執行。 Linux中程序執行時的記憶體映像如下:

C程式編譯過程淺析

我現在一般都是用gcc,所以自然以GCC編譯hellworld為例,簡單總結如下。  hello.c原始碼如下: /* 何問起 hovertree.com */ int main() { printf(“Hello, world.\n”); return 0; } 通常我們使用gcc

c++程式編譯過程

編譯主要分為4個過程: 預處理-編譯優化-彙編-連結 1) 編譯預處理 預編譯程式完成的工作,可以說成是對源程式的“替換”工作。經過這個過程,生成一個沒有巨集定義、沒有條件編譯指令、沒有特殊符號的輸出檔案。 巨集定義命令;例如#define 條件編譯指

C++ —— C++程式編譯的四個過程

C++ —— C++程式編譯的四個過程        g++是Linux下C++的編譯器;我為什麼會選擇Linux下的g++編譯器,就是因為g++可以看到程式從編譯到執行的過程做了些什麼。而VS等整合開發環境看不到這些,並不是說VS工具不好,(VS還是相當好用的...)。

GCC 顯示程式詳細編譯-連結過程

   很多時候,我們對於程式的編譯和連結過程很少關注。特別是使用強大的IDE之後,更多人只是會使用IDE進行程式設計。這樣,一旦出現編譯或者連結問題,有時候會很難找到編譯或者連結問題。理解編譯和連結的過程,對於編寫程式以及除錯問題都有很大的幫助。    事實上,gcc提供了

C語言C++程式設計師應聘過程中應當注意些什麼?

既然是面試,一定要提前準備,最好準備一套自我介紹,包括對IT行業的看法之類,面試官經常會問這些問題。 由於c語言是程式設計師工作語種的其中1個,所以對於程式設計師這個工種,還是有一些具體的注意事項: (C/C++企業實戰級課程資源(素材+原始碼+視訊)、編譯大禮包免費分享,需要的加學習群89

面試題9——簡述CC++程式編譯的記憶體分配情況

一個C,C++程式編譯時記憶體分為5大儲存區:堆區,棧區,全域性區,文字常量區,程式程式碼區。 C,C++中記憶體分配方式可以分為三種: (1)從靜態儲存區域分配: 記憶體在程式編譯時就已經分配好,這塊記憶體在程式的整個執行期間都存在。例如全域性變數,static變數等。 (2)在棧上分