深圳網(wǎng)站建設 推薦xtdseo百度系app有哪些
前言:
? ? ? ? 由于c語言的程序編譯鏈接的這塊知識點不清楚,回來復習一遍,以便于好理解c++知識,我會盡快更新下一篇文章。
目錄
1.程序的翻譯環(huán)境和執(zhí)行環(huán)境
2.翻譯環(huán)境(編譯+鏈接)
編譯(編譯器)
預編譯(預處理)
1.頭文件的包含
2.注釋的測試
編譯過程
匯編過程
鏈接
1.合并段表
2.符號表的合并和重定位
計算機語言的發(fā)展
運行環(huán)境(翻譯之后)
3.預處理詳解?
3.1 預定義符號
3.2 #define
3.2.1 #define 定義標識符
3.2.2 #define 定義宏 ?
3.2.3#define 替換規(guī)則
3.2.4 #和##
3.2.5 帶副作用的宏參數(shù)
1.程序的翻譯環(huán)境和執(zhí)行環(huán)境
總體過程:
在ANSI C的任何一種實現(xiàn)中,存在兩個不同的環(huán)境
第1種是翻譯環(huán)境,在這個環(huán)境中源代碼被轉(zhuǎn)換為可執(zhí)行的機器指令。
第2種是執(zhí)行環(huán)境,它用于實際執(zhí)行代碼。
2.翻譯環(huán)境(編譯+鏈接)
我們常說一個test.c文件要經(jīng)過以下步驟才能產(chǎn)生可執(zhí)行的程序,那么具體是怎么做到的呢?
在vs編譯器上是要經(jīng)過以下過程的:
源文件和目標文件的關(guān)系:
????????VS是一個集成開發(fā)環(huán)境,集成很多的功能ctr1+F5,不方便觀察每個細節(jié)的功能接下來,我使用gcc這個編譯器給大家演示
????????由于上圖的操作把這個編譯運行的步驟一次走完了,我們一步步來,咱們用指令讓程序停在預編譯的階段:
編譯(編譯器)
預編譯(預處理)
將控制臺的內(nèi)容放到test.i之后,預處理階段所做的事情:
1.頭文件的包含
2.注釋的測試
編譯過程
功能:把C語言代碼翻譯成匯編代碼
1.語法分析
2.詞法分析
3.語義分析
4.符號匯總函數(shù)名,全局變量, 不會匯總 局部變量(函數(shù)運行起來才行)![]()
鏈接:https://pan.baidu.com/s/1cVcZRTj772hJXm0mO0Q_cw?pwd=1234?
提取碼:1234

匯編過程
1.把匯編代碼轉(zhuǎn)換成二進制的指令
2.形成符號表?
鏈接
1.合并段表
2符號表的合并和重定位
1、2的作用其實是在鏈接期間為這種跨文件的代碼進行協(xié)作的時候起作用的。
在vscode中操作:
過程:
1.合并段表
2.符號表的合并和重定位
? ? ? ? 把無效的地址給替換掉,符號表和段表的關(guān)系是:符號表是段表的內(nèi)容
那該如何體現(xiàn)這個作用呢?
????????假設我們在test.c文件底下extern了一個函數(shù)Add,但是在add.c底下沒有實現(xiàn)這個Add函數(shù),就會輸出以下錯誤(鏈接型錯誤)
? ? ? ? 如果說這個函數(shù)寫錯的話,在main函數(shù)內(nèi)調(diào)用大寫的,但是在add.c內(nèi)定義成小寫的,是依然找不到
計算機語言的發(fā)展
運行環(huán)境(翻譯之后)
1. 程序必須載入 內(nèi)存 中。在有操作系統(tǒng)的環(huán)境中:一般這個由操作系統(tǒng)完成。在獨立的環(huán)境中,程序的載入必須由手工安排,也可能是通過可執(zhí)行代碼置入只讀內(nèi)存來完成。2. 程序的執(zhí)行便開始。接著便調(diào)用 main 函數(shù)(main函數(shù)第一行開始)3. 開始執(zhí)行程序代碼。這個時候程序?qū)⑹褂靡粋€運行時堆棧( stack )-- 函數(shù)棧幀 ,存儲函數(shù)的局部變量和返回地址。 程序同時也可以使用靜態(tài)(static)內(nèi)存,存儲于靜態(tài)內(nèi)存中的變量在程序的整個執(zhí)行過程一直保留他們的值。4. 終止程序。正常終止 main 函數(shù);也有可能是意外終止。
3.預處理詳解?
3.1 預定義符號
__FILE__ ? ? ? //進行編譯的源文件__LINE__ ? ? //文件當前的行號__DATE__ ? ? //文件被編譯的日期__TIME__ ? ? //文件被編譯的時間
執(zhí)行:
__STDC__ ? ?//如果編譯器遵循ANSI C,其值為1,否則未定義
?而放在gcc編譯器上面是可以執(zhí)行通過的:
????????編譯器在代碼編譯的時候,會對函數(shù)和變量名重命名的,C++ 中會更加復雜
????????在C語言中重命名的規(guī)則基本就是:加_
3.2 #define
3.2.1 #define 定義標識符
語法:#define name stuff
全部例子:?
#define MAX 1000
#define reg register ? ? ? ? ?//為 register這個關(guān)鍵字,創(chuàng)建一個簡短的名字
#define do_forever for(;;) ? ? //用更形象的符號來替換一種實現(xiàn)
#define CASE break;case ? ? ? ?//在寫case語句的時候自動把 break寫上。
// 如果定義的 stuff過長,可以分成幾行寫,除了最后一行外,每行的后面都加一個反斜杠(續(xù)行符)。
#define DEBUG_PRINT printf("file:%s\tline:%d\t \date:%s\ttime:%s\n" ,\__FILE__,__LINE__ , ? ? ? \__DATE__,__TIME__ )
#define MAX 1000

?#define reg register//為 register這個關(guān)鍵字,創(chuàng)建一個簡短的名字 ?
#define do_forever for(;;)//用更形象的符號來替換一種實現(xiàn)?
#define CASE break;case //在寫case語句的時候自動把 break寫上。

長行如何拆分,\后面只能是換行,不能是其他?
?如果定義的 stuff過長,可以分成幾行寫,除了最后一行外,每行的后面都加一個反斜杠(續(xù)行符)。

在define定義標識符的時候,要不要在最后加上 ; ?
#define MAX 1000;#define MAX 1000

if ( condition )????????max = MAX ;else????????max = 0 ;
這里會出現(xiàn)語法錯誤.
3.2.2 #define 定義宏 ?
#define name( parament-list ) stuff其中的 parament - list 是一個由逗號隔開的符號表,它們可能出現(xiàn)在 stuff 中
#define SQUARE( x ) x * x
SQUARE ( 5 );
5 * 5

int a = 5 ;printf ( "%d\n" , SQUARE ( a + 1 ) );

替換文本時,參數(shù)x被替換成a + 1,所以這條語句實際上變成了:printf ("%d\n",a + 1 * a + 1 );
#define SQUARE(x) (x) * (x)

printf ( "%d\n" ,( a + 1 ) * ( a + 1 ) );
#define DOUBLE(x) (x) + (x)
定義中我們使用了括號,想避免之前的問題,但是這個宏可能會出現(xiàn)新的錯誤。
int a = 5 ;printf ( "%d\n" , 10 * DOUBLE ( a ));
printf ("%d\n",10 * (5) + (5));
#define DOUBLE( x) ? ( ( x ) + ( x ) )
所以用于對數(shù)值表達式進行求值的宏定義都應該用這種方式加上括號,避免在使用宏時由于參數(shù)中的操作符或鄰近操作符之間不可預料的相互作用。
所以這就涉及到#define的替換規(guī)則了
3.2.3#define 替換規(guī)則
在程序中擴展 #define 定義符號和宏時,需要涉及幾個步驟。????????1. 在調(diào)用宏時,首先對參數(shù)進行檢查,看看是否包含任何由 #define 定義的符號。如果是,它們首先被替換。????????2. 替換文本隨后被插入到程序中原來文本的位置。對于宏,參數(shù)名被他們的值所替換。????????3. 最后,再次對結(jié)果文件進行掃描,看看它是否包含任何由 #define 定義的符號。如果是,就重復上述處理過程。
3.2.4 #和##
如何把參數(shù)(變量名)插入到字符串中?
首先我們看看這樣的代碼:
char* p = "hello ""bit\n";
printf("hello"" bit\n");
printf("%s", p);
?這里輸出的是不是hello bit ?
? ? ? ? 請看下圖,有沒有那么一條語句,將這三個變量傳參傳過去,然后實現(xiàn)它們各自的輸出呢??
現(xiàn)在定義一個宏
#define print_format(num, format) \?printf("the value of #num is "format)
并且讓它輸出:
這時候發(fā)現(xiàn)需要正確輸入它們的數(shù)值:
## 可以把位于它兩邊的符號合成一個符號。它允許宏定義從分離的文本片段創(chuàng)建標識符。

3.2.5 帶副作用的宏參數(shù)
x + 1 ; //不帶副作用x ++ ; //帶有副作用
在vscode2019內(nèi)調(diào)試一下:
? ? ? ? 想知道宏和函數(shù)的區(qū)別嗎,欲知后事如何,請聽下回分解。