C語言程序的編譯與預(yù)處理基礎(chǔ)定義講解
程序的翻譯環(huán)境和執(zhí)行環(huán)境
在ANSIC的任何一種實現(xiàn)中,存在兩個不同的環(huán)境:翻譯環(huán)境和執(zhí)行環(huán)境
翻譯環(huán)境:源代碼被轉(zhuǎn)換為可執(zhí)行的機器指令。
執(zhí)行環(huán)境:實際執(zhí)行代碼。
1.翻譯環(huán)境
- 組成一個程序的每個源文件通過編譯分別轉(zhuǎn)換成目標文件(object code)。
- 每個目標文件由鏈接器(linker)捆綁在一起,形成一個單一而完整的可執(zhí)行程序。
- 鏈接器同時也會引入標準C函數(shù)庫中任何被該程序所用到的函數(shù),而且它可以搜索程序員個人的程序庫,將齊需要的函數(shù)也鏈接到程序中。
2.運行環(huán)境
程序的執(zhí)行環(huán)境:
1.程序必須載入內(nèi)存中。在有操作系統(tǒng)的環(huán)境中:一般這個由操作系統(tǒng)完成。在獨立的環(huán)境中,程序的載入必須由手工安排,也可能是通過可執(zhí)行代碼置入只讀內(nèi)存來完成。
2.程序的執(zhí)行便開始。接著便調(diào)用main函數(shù)。
3.開始執(zhí)行程序代碼。這個時候程序?qū)⑹褂靡粋€運行時堆棧(stack),存儲函數(shù)的局部變量和返回地址。程序同時也可以使用靜態(tài)(static)內(nèi)存,存儲于靜態(tài)內(nèi)存中的變量在程序的整個執(zhí)行過程中一種保留它們的值。
4.終止程序。正常終止main函數(shù),也有可能是意外終止。
預(yù)處理詳解
預(yù)定義符號
#define
#define 定義標識符
語法:
#define name stuff
#define MAX 100 #define REG register //為register創(chuàng)建一個簡短的名字 #define do_forever for(;;) //用符號來替換一種實現(xiàn) #define PRINT printf("file:%s\tline:%d\tdate:%s\time:%s\n", \ __FILE__,__LINE__,__DATE__,__TIME__) //如果定義的stuff過長,可以分成幾行來寫,除了最后一行外,每行的后面都加一個反斜杠(續(xù)行符)。
在define定義標識符的時候,最后不要加(;)號。
#define定義宏
#define機制包括了一個規(guī)定,允許把參數(shù)替換到文本中,這種實現(xiàn)通常稱為宏(macro)或定義宏(define macro)。
宏的聲明方式:
#define name ( parament - list ) stuff
其中的parament - list 是一個由逗號隔開的符號表,它們可能出現(xiàn)在stuff中。
參數(shù)列表的左括號必須與name緊緊相鄰。若兩者之間存在空白,參數(shù)列表就會被解釋為stuff的一部分。
#define SQUARE( x ) x * x
#define替換規(guī)則
1.在調(diào)用宏時,首先對參數(shù)進行檢查,看看是否包含任何由#define定義的符號。如果是,它們將首先被替換。
2.替換文本隨后被插入到程序中原來文本的位置。對于宏,參數(shù)名被它們的值替換。
3.最后,再一次對結(jié)果文件進行掃描,看看是否還包含任何由#define定義的符號。如果是,就重復(fù)上述的過程。
注意:
1.宏參數(shù)和#define定義中可以出現(xiàn)其它#define定義的變量。但是對于宏,不能出現(xiàn)遞歸。
2.當預(yù)處理器搜索#define定義的符號的時候,字符串常量的內(nèi)容并不被搜索。
#和##
如何把參數(shù)插入到字符串中?
#include<stdio.h> #define PRINT(n) printf("the value of "#n" is %d\n",n) int main() { int a = 7; PRINT(a); int b = 5; PRINT(b); return 0; }
##的作用:
帶副作用的宏參數(shù)
當宏參數(shù)在宏的定義中出現(xiàn)超過一次的時候,如果參數(shù)帶有副作用,那么在使用這個宏的時候就可能會出現(xiàn)危險,導(dǎo)致不可預(yù)知的后果。副作用就是表達式求值的時候出現(xiàn)的永久性效果。
x+1;//不帶有副作用 x++;//帶有副作用
舉一個例子:
宏和函數(shù)對比
宏通常被應(yīng)用于執(zhí)行簡單的運算。例如在找出兩個數(shù)中的較大一個。
#define MAX(a, b) ((a)>(b)?(a):(b))
為什么不用函數(shù)來完成這個任務(wù)呢?有其下原因:
1.用于調(diào)用函數(shù)和從函數(shù)返回的代碼可能比實際執(zhí)行這個小型計算工作所需要的時間更多。所以宏比函數(shù)在程序的規(guī)模和速度方面更勝一籌。
2.函數(shù)的參數(shù)必須聲明為特定的類型。所以函數(shù)只能在類型合適的表達式上使用。而這個宏可以適用于整形、長整型、浮點型等類型。宏是類型無關(guān)的。
宏和函數(shù)的對比:
命名約定
一般來講函數(shù)和宏的使用語法非常相似。所以語法本身沒有辦法幫我們區(qū)分二者。
所以一般是:把宏名全部大寫,函數(shù)名不要全部大寫。
#undef
這條指令用于移除一個宏定義。
#undef NAME //如果現(xiàn)存的一個名字需要被重定義,那么它的舊名字首先要被移除
例如:
命令行定義
許多C的編譯器提供了一種功能,允許程序在命令行中定義符號。用于啟動編譯過程。
例如:當我們根據(jù)同一個源文件要編譯出不同的一個程序的不同版本的時候,這個特性就比較有用。(若某個程序中聲明了一個某長度的數(shù)組,若機器內(nèi)存有限,我們需要一個很小的數(shù)組,若機器內(nèi)存大一些,我們就需要一個大一點的數(shù)組)。
條件編譯
在編譯一個程序的時候如果要將一條語句或者一組語句編譯或者放棄是很方便的。可以用條件編譯指令。
常見的條件編譯指令:
文件包含
#include指令可以使另外一個文件被編譯。
這種替換的方式:預(yù)處理先刪除這條指令,并用包含文件的內(nèi)容替換。這樣一個源文件被包含幾次,那就實際被編譯幾次。
頭文件被包含的方式:
通常一個大型的項目會調(diào)用多個程序合并,那么如何避免頭文件的重復(fù)包含而提高效率呢?
常見的有一下兩種解決方法:
1.每個頭文件的開頭寫:
#ifndef __TEST_H__ #define __TEST_H__ //頭文件的內(nèi)容 #endif
2.定義頭文件之前包含這一句話:
#pragma once
到此這篇關(guān)于C語言程序的編譯與預(yù)處理基礎(chǔ)定義講解的文章就介紹到這了,更多相關(guān)C語言編譯與預(yù)處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解析C/C++指針、函數(shù)、結(jié)構(gòu)體、共用體
這篇文章主要介紹了C/C++指針、函數(shù)、結(jié)構(gòu)體、共用體的相關(guān)知識,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-01-01C++與Java分別解決活動選擇問題和帶權(quán)活動選擇問題
這篇文章介紹了C++與Java分別解決活動選擇問題和帶權(quán)活動選擇問題,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06c++ Protobuf解決數(shù)據(jù)傳輸瓶頸面試精講
這篇文章主要介紹了c++ Protobuf解決數(shù)據(jù)傳輸瓶頸利器面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-10-10