程序的编译和链接过程
生活随笔
收集整理的這篇文章主要介紹了
程序的编译和链接过程
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
一.虛擬機(jī)、linux簡介
簡單介紹一下虛擬機(jī)還有就是各種操作系統(tǒng),比如centos,Ubuntu
操作系統(tǒng):linux(centos、Ubuntu、redhat),Android,Windows(xp、win8、win10)
進(jìn)程,多個(gè)程序,分時(shí)技術(shù),并行技術(shù)
一次打開多個(gè)程序,我們?cè)谥挥幸粋€(gè)cpu,如何讓這些程序進(jìn)行執(zhí)行呢,看起來好像是在同時(shí)進(jìn)行的,實(shí)際上是一個(gè)程序執(zhí)行了一點(diǎn)點(diǎn)時(shí)間,然后保存執(zhí)行的一些信息,接下來回來再次執(zhí)行,這樣就達(dá)到了看上去是多個(gè)程序在同時(shí)執(zhí)行的效果
操作系統(tǒng)的作用:控制程序的執(zhí)行,管理系統(tǒng)的資源
二.程序的編譯鏈接過程
2.1首先看一下預(yù)處理的指令
關(guān)于上面的預(yù)處理指令,大家可以自己測試一下
(測試?yán)?#xff09;(注意是兩行) ANSI 標(biāo)準(zhǔn) C 定義的幾個(gè)宏如下,大家可以簡單的了解一下 __LINE__ 表示正在編譯的文件的行號(hào) __FILE__ 表示正在編譯的文件的名字 __DATE__ 表示編譯時(shí)刻的日期字符串,例如: "25 Dec 2007" __TIME__ 表示編譯時(shí)刻的時(shí)間字符串,例如: "12:30:55" __STDC__ 判斷該文件是不是定義成標(biāo)準(zhǔn) C 程序
2.2宏定義 編譯器在預(yù)處理的時(shí)候,就會(huì)把宏定義的數(shù)據(jù)替換成它的元身,這里我們必須了解什么是宏,宏的主要的用法 2.2.1 定義宏常量 #define PI 3.14159265358979323846264338327 比如我們經(jīng)常使用的一個(gè)變量,如果這個(gè)變量的數(shù)值改變了之后,我們不需要再文件里面一個(gè)一個(gè)找,而是只需要把宏改變就可以了 #define ERROR_TEST -1 比如我們?cè)趖est文件中,一些代碼的地方需要使用return -1,或者是exit(-1) 然后有很多類型的錯(cuò)誤返回,如果每次返回的是-1,-2,-3之類的,一會(huì)就把自己給繞暈了 2.2.2定義字符串常量 #define PATH "c/file/linux" 這個(gè)一般用在表示文件的路徑的情況下有很多 (大家下去看一下,如果是一行寫不下怎么辦呢,就是比如一行太長了怎么辦) 2.2.3 定義注釋 #define ZZ // 因?yàn)樵诔绦蚓幾g的時(shí)候,注釋是先于宏處理的 2.2.4 定義表達(dá)式(宏函數(shù)) #define MUL(x) x*x 純文本替換 測試用例 MUL(5);MUL(1+2); --- 加上括號(hào)MUL((x)*(x)) MUL(5*3)*MUL(5*3) --- 大括號(hào)???不要吝嗇括號(hào) 2.2.5 空格 #define MUL (x) ((x)*(x)) 比如上面的宏函數(shù),我們要是定義成下面的這個(gè)樣子又是什么樣的呢 2.2.6#undef 撤銷宏定義 比如 #define PI 3.14159265358979323846264338327 ... ... ... #undef PI此時(shí)PI不在有效了 2.2.7定義宏函數(shù)補(bǔ)充 比如下面的程序 #define PRINTF printf("測試");
這個(gè)時(shí)候我們可以編寫 一個(gè)if esle語句 if(0) PRINTF; else printf("haha\n");
宏函數(shù)比普通函數(shù)的一些特性在哪里 (1)普通的函數(shù)需要建立棧幀,開銷較大,宏函數(shù)在效率上面更勝一籌 (2)函數(shù)中的參數(shù)必須使用特定的類型,換句話說,宏函數(shù)對(duì)參數(shù)是不進(jìn)行類型檢查的,宏函數(shù)是不類型限制的
宏函數(shù)的缺點(diǎn) 宏函數(shù)每次是進(jìn)行的代碼的替換,有時(shí)候可能會(huì)增加代碼的長度,使維護(hù)起來非常的復(fù)雜 宏函數(shù)的參數(shù)不能是一個(gè)類型
2.3. 條件編譯 第一種形式: #ifdef 標(biāo)識(shí)符 程序段 1 #else 程序段 2 #endif 它的功能是,如果標(biāo)識(shí)符已被 #define 命令定義過則對(duì)程序段 1 進(jìn)行編譯;否則對(duì)程序段 2 進(jìn)行編譯。
第二種形式 #ifndef 標(biāo)識(shí)符程序段 1 #else 程序段 2 #endif
第三種形式 #if 常量表達(dá)式 程序段 1 #else 程序段 2 #endif
2.4. 文件包含 文件包含是預(yù)處理的一個(gè)重要功能,它可用來把多個(gè)源文件連接成一個(gè)源文件進(jìn)行編譯,結(jié)果將生成一個(gè)目標(biāo)文件。C語言提供#include 命令來實(shí)現(xiàn)文件包含的操作,它實(shí)際是宏替換的延伸,有兩種格式: #include<filename> #include"filename" 2.5.#pragma 預(yù)處理 自己上網(wǎng)調(diào)研,寫博客,寫測試用例 #pragma once #pragma warning #pragma pack--這個(gè)是張晨亮學(xué)長給你們講過的,設(shè)置內(nèi)置內(nèi)存對(duì)齊數(shù)
2.6詳解程序編譯和鏈接過程 程序的編譯和鏈接的過程 我們?cè)趌inux下使用gcc編譯器直接對(duì)程序進(jìn)行編譯,比如使用gcc test.c,然后就會(huì)生成一個(gè)程序叫做test.out 但是上面的看似簡單的過程實(shí)際上是經(jīng)歷了四個(gè)階段 預(yù)處理,編譯,匯編,連接 每個(gè)過程都有自己要完成的任務(wù)
記住一些操作,ESc對(duì)應(yīng)的是iso,
2.6.1. 預(yù)處理 通過預(yù)處理生成一個(gè).i的文件,使用的指令是 gcc -E test.c -o test.i (G) 預(yù)處理過程主要處理的是1. 以#開始的預(yù)處理指令(保留#pragma)2.刪除所有的注釋3.添加文件名和行號(hào),具體的過程如下
推薦書目:《程序員的自我修養(yǎng)--鏈接、裝載與庫》 《C語言深度剖析》
二.程序的編譯鏈接過程
2.1首先看一下預(yù)處理的指令
關(guān)于上面的預(yù)處理指令,大家可以自己測試一下
(測試?yán)?#xff09;(注意是兩行) ANSI 標(biāo)準(zhǔn) C 定義的幾個(gè)宏如下,大家可以簡單的了解一下 __LINE__ 表示正在編譯的文件的行號(hào) __FILE__ 表示正在編譯的文件的名字 __DATE__ 表示編譯時(shí)刻的日期字符串,例如: "25 Dec 2007" __TIME__ 表示編譯時(shí)刻的時(shí)間字符串,例如: "12:30:55" __STDC__ 判斷該文件是不是定義成標(biāo)準(zhǔn) C 程序
2.2宏定義 編譯器在預(yù)處理的時(shí)候,就會(huì)把宏定義的數(shù)據(jù)替換成它的元身,這里我們必須了解什么是宏,宏的主要的用法 2.2.1 定義宏常量 #define PI 3.14159265358979323846264338327 比如我們經(jīng)常使用的一個(gè)變量,如果這個(gè)變量的數(shù)值改變了之后,我們不需要再文件里面一個(gè)一個(gè)找,而是只需要把宏改變就可以了 #define ERROR_TEST -1 比如我們?cè)趖est文件中,一些代碼的地方需要使用return -1,或者是exit(-1) 然后有很多類型的錯(cuò)誤返回,如果每次返回的是-1,-2,-3之類的,一會(huì)就把自己給繞暈了 2.2.2定義字符串常量 #define PATH "c/file/linux" 這個(gè)一般用在表示文件的路徑的情況下有很多 (大家下去看一下,如果是一行寫不下怎么辦呢,就是比如一行太長了怎么辦) 2.2.3 定義注釋 #define ZZ // 因?yàn)樵诔绦蚓幾g的時(shí)候,注釋是先于宏處理的 2.2.4 定義表達(dá)式(宏函數(shù)) #define MUL(x) x*x 純文本替換 測試用例 MUL(5);MUL(1+2); --- 加上括號(hào)MUL((x)*(x)) MUL(5*3)*MUL(5*3) --- 大括號(hào)???不要吝嗇括號(hào) 2.2.5 空格 #define MUL (x) ((x)*(x)) 比如上面的宏函數(shù),我們要是定義成下面的這個(gè)樣子又是什么樣的呢 2.2.6#undef 撤銷宏定義 比如 #define PI 3.14159265358979323846264338327 ... ... ... #undef PI此時(shí)PI不在有效了 2.2.7定義宏函數(shù)補(bǔ)充 比如下面的程序 #define PRINTF printf("測試");
這個(gè)時(shí)候我們可以編寫 一個(gè)if esle語句 if(0) PRINTF; else printf("haha\n");
宏函數(shù)比普通函數(shù)的一些特性在哪里 (1)普通的函數(shù)需要建立棧幀,開銷較大,宏函數(shù)在效率上面更勝一籌 (2)函數(shù)中的參數(shù)必須使用特定的類型,換句話說,宏函數(shù)對(duì)參數(shù)是不進(jìn)行類型檢查的,宏函數(shù)是不類型限制的
宏函數(shù)的缺點(diǎn) 宏函數(shù)每次是進(jìn)行的代碼的替換,有時(shí)候可能會(huì)增加代碼的長度,使維護(hù)起來非常的復(fù)雜 宏函數(shù)的參數(shù)不能是一個(gè)類型
2.3. 條件編譯 第一種形式: #ifdef 標(biāo)識(shí)符 程序段 1 #else 程序段 2 #endif 它的功能是,如果標(biāo)識(shí)符已被 #define 命令定義過則對(duì)程序段 1 進(jìn)行編譯;否則對(duì)程序段 2 進(jìn)行編譯。
第二種形式 #ifndef 標(biāo)識(shí)符程序段 1 #else 程序段 2 #endif
第三種形式 #if 常量表達(dá)式 程序段 1 #else 程序段 2 #endif
2.4. 文件包含 文件包含是預(yù)處理的一個(gè)重要功能,它可用來把多個(gè)源文件連接成一個(gè)源文件進(jìn)行編譯,結(jié)果將生成一個(gè)目標(biāo)文件。C語言提供#include 命令來實(shí)現(xiàn)文件包含的操作,它實(shí)際是宏替換的延伸,有兩種格式: #include<filename> #include"filename" 2.5.#pragma 預(yù)處理 自己上網(wǎng)調(diào)研,寫博客,寫測試用例 #pragma once #pragma warning #pragma pack--這個(gè)是張晨亮學(xué)長給你們講過的,設(shè)置內(nèi)置內(nèi)存對(duì)齊數(shù)
2.6詳解程序編譯和鏈接過程 程序的編譯和鏈接的過程 我們?cè)趌inux下使用gcc編譯器直接對(duì)程序進(jìn)行編譯,比如使用gcc test.c,然后就會(huì)生成一個(gè)程序叫做test.out 但是上面的看似簡單的過程實(shí)際上是經(jīng)歷了四個(gè)階段 預(yù)處理,編譯,匯編,連接 每個(gè)過程都有自己要完成的任務(wù)
記住一些操作,ESc對(duì)應(yīng)的是iso,
2.6.1. 預(yù)處理 通過預(yù)處理生成一個(gè).i的文件,使用的指令是 gcc -E test.c -o test.i (G) 預(yù)處理過程主要處理的是1. 以#開始的預(yù)處理指令(保留#pragma)2.刪除所有的注釋3.添加文件名和行號(hào),具體的過程如下
- 將所有的#define刪除,展開所有的宏定義
- 處理所有的條件預(yù)編譯指令,比如#if,#ifdef....
- 處理所有的#include預(yù)編譯指令,將所有被包含的文件包含至本文件中來
- 刪除所有的注釋,//和/* */等
- 保留所有的#pragma預(yù)處理指令,因?yàn)橄旅孢€要用到它
推薦書目:《程序員的自我修養(yǎng)--鏈接、裝載與庫》 《C語言深度剖析》
總結(jié)
以上是生活随笔為你收集整理的程序的编译和链接过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《我是歌手》,如果退赛会对比赛造成什么影
- 下一篇: vim编辑文章后不能修改