33 C語言巨集定義和預處理

2021-07-11 02:13:48 字數 4234 閱讀 5102

33.1.原始碼到可執行程式過程

(1)原始碼.c檔案->(編譯)->elf可執行程式。

(2)原始碼.c->(編譯)->目標檔案.o->(鏈結)->elf可執行程式。

(3)原始碼.c->(編譯)->彙編檔案.s->(彙編)->目標檔案.o->(鏈結)->elf可執行程式。

(4)原始碼.c->(預處理)->預處理過的.i原始檔->(編譯)->彙編檔案.s->(彙編)->目標檔案.o->(鏈結)->elf可執行程式。

(5)預處理用預處理器,編譯用編譯器,彙編用彙編器,鏈結用鏈結器,這些工具再加上額外的會用到的工具組成編譯工具鏈,gcc就是某個編譯工具鏈。

33.2.預處理的意義及程式設計應用

(1)編譯器本身的主要目的是編譯源**,將c的源**轉化成.s的彙編**;編譯器聚焦核心功能後,就剝離出某些非核心的功能到預處理器;預處理器幫編譯器做一些編譯前的雜事。

(2)預處理階段的主要工作:標頭檔案包含(#include);注釋;條件編譯(#if #elif #endif/#ifdef);巨集定義。

(3)配置gcc實現只預處理不編譯:gcc編譯時可以給某些引數來設定,譬如gcc xx.c -o xx即指定可執行程式的名稱,譬如gcc xx.c -c -o xx.o即指定只編譯不鏈結,譬如gcc -e xx.c -o xx.i即實現只預處理不編譯;通常情況下我們沒必要只預處理不編譯,但有時該技巧可幫助我們研究預處理過程,幫助debug程式。

(4)巨集定義被預處理後的現象:第1巨集定義語句本身不見了,則編譯器根本就不知道#define巨集;第2typedef重新命名語言沒變,則typedef是由編譯器來處理的。

33.3.標頭檔案包含

(1)#include<>和#include」「的區別:<>專門用來包含系統提供的標頭檔案;」「用來包含程式設計師自己寫的標頭檔案。

(2)<>包含標頭檔案:c語言編譯器只會到系統指定目錄(編譯器/作業系統配置的目錄,譬如在ubuntu中是/usr/include目錄,編譯器允許用-i來附加指定其它的包含路徑)去尋找該標頭檔案,若沒找到則提示該標頭檔案不存在,注意編譯器不會在當前目錄下尋找該標頭檔案。

(3)」「包含的標頭檔案,編譯器缺省會先在當前目錄下尋找該標頭檔案,若沒找到則再到系統指定目錄去尋找,若還沒找到則提示該標頭檔案不存在。

(4)總結:若包含系統指定的自帶的標頭檔案用<>;若標頭檔案是自己寫的存放在當前目錄下用」「;若標頭檔案是自己寫的但集中存放在某個目錄下將來在編譯器中用-i引數來尋找,此時標頭檔案包含用<>。

(5)標頭檔案包含的真實含義:在包含標頭檔案的那一行,將標頭檔案的內容原地展開替換包含標頭檔案的語句,替換過程在預處理中進行。

33.4.注釋和條件編譯

(1)注釋是給人看的,不是給編譯器看的;在預處理階段時預處理器會拿掉程式中所有的注釋語句,到了編譯器編譯階段程式中已經沒有注釋了。

(2)條件編譯即有時候我們希望程式有多種配置(源**編輯階段給每個配置開關編寫了相應的原始碼),在源**級別去修改配置開關來讓程式編譯出不同的效果。

(3)條件編譯中條件判斷標準:#ifdef和#if;#ifdef ***(其判斷標準是***該符號在本語句之前是否被定義,只要定義了則表示式成立(#define ***或#define *** 12或#define *** yyy));#if(條件表示式)(判定標準是()中的表示式是否為true還是flase,類似c中的if語句)。

33.5.巨集定義的規則和使用解析

(1)巨集定義的解析規則:在預處理階段由預處理器進行原封不動的替換;巨集定義替換會遞迴進行,直到替換出來的值本身不再是某個巨集為止。

(2)巨集定義格式:第1部分是#dedine,第2部分是巨集名,第3部分為剩下的全部東西。

(3)巨集可以帶引數(帶參巨集),帶參巨集的原理類似帶參函式,在定義帶參巨集時,每個引數在巨集體中引用時都必須加括號,最後整體再加括號,括號缺一不可。

(4)巨集定義示例1:max巨集,求2個數中較大的乙個:#define max(a, b) (((a)>(b)) ? (a) : (b))(使用三目運算子;括號的使用)。

(5)巨集定義示例2:sec_per_year巨集,用巨集定義表示一年中有多少秒:#define sec_per_year (365*24*60*60ul)(當某個數字直接出現在程式中時,其型別預設是int;一年有多少秒該數字超過了int型別儲存的範圍)。

33.6.帶參巨集和帶參函式的區別

(1)巨集定義是在預處理期間處理的,而函式是在編譯期間處理的;巨集定義最終是在呼叫巨集的地方把巨集體原地展開,而函式是在呼叫函式處跳轉到函式中去執行,執行完後再跳轉回來;巨集定義是原地(沒有呼叫開銷),而函式是跳轉執行再返回(有較大的呼叫開銷);則巨集的優勢是沒有呼叫和傳參開銷,當函式體很短可以用巨集定義來替代,以提高效率。

(2)巨集定義不會檢查引數的型別,返回值也不會附帶型別;而函式有明確的引數型別和返回值型別,當我們呼叫函式時編譯器會幫我們做引數的靜態型別檢查。

(3)巨集和函式各優劣:若**比較多用函式適合而且不影響效率(編譯器會進行靜態型別檢查);但若**較短就適合用帶參巨集(巨集不會檢查引數型別)。

33.7.內聯函式和inline關鍵字

(1)內聯函式通過在函式定義前加inline關鍵字實現。

(2)內聯函式本質上是函式,所以有函式的優點(編譯器做引數靜態型別檢查);其也有帶參巨集的優點(原地展開沒有呼叫開銷);則幾乎可認為內聯函式就是帶了引數靜態型別檢查的巨集。

(3)當函式內函式體很短的時候,我們既希望利用編譯器的引數型別檢查來排錯,而且還希望沒有呼叫開銷時,最適合使用內聯函式。

33.8.巨集定義來實現條件編譯

(1)程式有debug版本和release版本,區別就是編譯時有無定義debug巨集。

(2)#define、#undef、#ifdef舉例:

/* * 公司:***x

* 部落格:

* github:

* 專案:c語言預處理詳解

* 功能:通過預處理.i檔案解釋#define和typedef的本質區別。

*/#if 0

32.preprocess.i檔案內容:

# 1 "33.preprocess.c"

# 1 ""

# 1 ""

# 1 "33.preprocess.c"

# 13 "33.preprocess.c"

typedef char * pchar

int main(int argc, char **argv)

#endif

#define pchar char *

typedef char * pchar;

int main(int argc, char **argv)

33.preprocess_if_ifdef

/* * 公司:***x

* 部落格:

* github:

* 專案:c語言預處理詳解

* 功能:條件編譯#ifdef和#if是使用方法。

*/#include

#define num

#define pre 1

int main(int argc, char **argv)

33.macro

/* * 公司:***x

* 部落格:

* github:

* 專案:c語言預處理詳解

* 功能:演示巨集定義的各種用法。

*/// 演示巨集的遞迴替換

#define m 10

#define num m

// 巨集定義示例1:max巨集,求2個數中較大的乙個

#define max(a, b) ((a)>(b) ? (a) : (b))

// 巨集定義示例2:sec_per_year巨集,用巨集定義表示一年中有多少秒

#define sec_per_year (365*24*60*60ul)

// 巨集定義來實現條件編譯

#define debug

//#undef debug // 登出debug巨集,若前面有定義debug巨集則取消該巨集

#ifdef debug

#define debug(x) printf(x)

#else

#define debug(x)

#endif

#include

int main(int argc, char **argv)

C語言 預處理和巨集定義

今天分享一點c語言的預處理還有巨集相關的內容。目錄 預處理和巨集定義 一 乙個c程式的誕生 1 預編譯階段 c i 2 編譯階段 i s 3 彙編階段 s o 4 鏈結階段 該程式的所有.o exe 1 c語言中部分內建巨集 2 巨集的功能 1 使用巨集定義常量 2 使用巨集重新命名運算子 3 使用...

C語言 巨集定義,預處理巨集

巨集是學習任何語言所不可缺少的,優秀的巨集定義可以使得 變得很簡潔且高效,有效地提高程式設計效率。巨集是一種預處理指令,它提供了一種機制,可以用來替換源 中的字串,直譯器或編譯器在遇到巨集時會自動進行這一模式替換 c語言有簡單的巨集系統,由編譯器或彙編器的預處理器實現。c的巨集預處理器的工作只是簡單...

c語言預處理 巨集定義

個人筆記 巨集定義對於用c語言程式設計的人是經常用,這裡只講使用中需注意的問題點和方便的用法。1.巨集擴充套件中空格對擴充套件結果的影響 define a y a expanded y a x 被擴充套件為 a expanded x define a y a expanded y a x 被擴充套件...