- 我們在編寫代碼的時候,不知道大家是否和一開始的我一樣,在運行代碼的時候就直接CTRL+F5運行了呢??一開始,我只知道會生成一個.exe的可執(zhí)行文件,中間的原理我一點也不知道。
- 今天就由我?guī)ьI(lǐng)大家對生成可執(zhí)行的文件有更深的一層理解。
?程序的翻譯環(huán)境和執(zhí)行環(huán)境
- 在ANSI C的任何一種實現(xiàn)中,存在兩個不同的環(huán)境。
- 第一種是翻譯環(huán)境,在這個環(huán)境中源代碼被轉(zhuǎn)換為可執(zhí)行的機器指令。第二種是執(zhí)行環(huán)境它用于 實際執(zhí)行代碼。
- ?組成一個程序的每個源文件通過編譯過程分別轉(zhuǎn)換目標代碼。
- 每個目標文件由鏈接器捆綁在一起,形成一個單一而完整的可執(zhí)行程序。
- 鏈接器同時也會引入標準C庫函數(shù)中任何被該程序所用到的函數(shù),而且它可以搜索程序員個人的程序庫,將其需要的函數(shù)鏈接到程序中。
翻譯也分為幾種過程:
- ?在預(yù)處理中,我們可以通過在Linux環(huán)境下,用gcc text.c -E -o text.i 來看一看在預(yù)處理中編譯器做了什么
- ?我們發(fā)現(xiàn)短短10行的代碼變成了700多行,這是因為在預(yù)處理中,包含的頭文件被展開了,而且宏已經(jīng)被替換了。
- 在這里,大家有沒有想過一個問題呢??在預(yù)處理階段中,到底是宏替換先執(zhí)行還是去注釋先執(zhí)行呢???
?
?文章來源地址http://www.zghlxwxcb.cn/news/detail-647498.html
- ?經(jīng)過證明,我們發(fā)現(xiàn)去注釋是先執(zhí)行的,如果是宏替換先執(zhí)行的話,那么就不會有Hello World的輸出了。
?
預(yù)定義的符號:
- _FILE_? //進行編譯的源文件
- _LINE_ //文件當(dāng)前的行號
- _DATE_ //文件被編譯的日期
- _TIME_ //文件被編譯的時間
- _STDC_ //如果編譯器遵循ANSI C ,其值為1,否則為定義
關(guān)于宏的定義,其實本質(zhì)上就是在預(yù)處理的階段被替換。
- 我們來看這個代碼就知道了,我們用宏定義了SQUARE ,如果沒有我剛剛說宏的本質(zhì)是替換是不是很多人會以為答案是36,經(jīng)過我上面說的,宏的本質(zhì)是替換,所以就替換成了printf("%d\n",5+1&1+5);這個,答案就是11??
#define SQUARE(x) x*x int main() { int a = 5; printf("%d\n", SQUARE(5 + 1)); return 0; }
?
宏的好處:
- ?在用于函數(shù)和從函數(shù)返回的代碼可能比實際執(zhí)行這個小型計算工作所需要的時間多,所以宏比函數(shù)在程序上的規(guī)模和速度上更勝一籌。
- 第二個就是宏是無關(guān)類型的
宏的壞處:
- 宏不能遞歸,也不好調(diào)試
- 參數(shù)可能被替換到宏體中的多個位置,所以帶有副作用的參數(shù)求值可能產(chǎn)生不可預(yù)料的問題
綜上所述,其實我更推薦用函數(shù),函數(shù)可以調(diào)試,而且在C++中用inline也綜合了宏和函數(shù)的優(yōu)缺點。
命名約定
?宏名全部大寫 函數(shù)名不要全部大寫
- 命令行定義
- 在許多C 的編譯器提供了一種能力,允許在命令行中定義符號。用于啟動編譯過程。 例如:當(dāng)我們根據(jù)同一個源文件要 編譯出不同的一個程序的不同版本的時候,這個特性有點用處。(假定某個程序中聲明了一個某個長度的數(shù)組,如果 機器內(nèi)存有限,我們需要一個很小的數(shù)組,但是另外一個機器內(nèi)存大寫,我們需要一個數(shù)組能夠大寫。)
- 比如,下面代碼我就用到了命令行定義
常見的預(yù)處理指令?
- #ifndef?
- #define
- #if
- #endif
- #elif
- ...
- 當(dāng)然還有很多預(yù)處理指令,這里就不再敘述了。
?
- 這里預(yù)處理指令中,我們常見的就是
- #ifndef include <stdio.h>
- #define include <stdio.h>
- #endif?
- 這里是為了不讓頭文件重復(fù)包含,在我們的第一個圖中就講到了,在預(yù)處理中頭文件會被展開,所以開text.i文件中會有700多行的代碼
- 當(dāng)然#pragma once也可以防止頭文件被重復(fù)包含
最后:講一講大家在做大型項目中,頭文件和定義總是分開的,都會用到#include "text.h"? 或#include <filename.h>,我來講一講它們之間的差別。
其實它們只是查找策略的不同,#include "filename.h"查找的策略是現(xiàn)在源文件所在的目錄下查找,如果找不到編譯器就會查找?guī)旌瘮?shù)頭文件一樣在標準位置查找頭文件。如果找不到就提示編譯錯誤
而#include <filename.h> 是直接查找?guī)旌瘮?shù)頭文件中的標準位置中查找頭文件文章來源:http://www.zghlxwxcb.cn/news/detail-647498.html
?
到了這里,關(guān)于C語言——可執(zhí)行程序過程的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!