C語言 預處理和巨集定義

2021-10-11 15:10:00 字數 4292 閱讀 7551

今天分享一點c語言的預處理還有巨集相關的內容。

目錄

預處理和巨集定義

一、乙個c程式的誕生

1、預編譯階段(.c-->.i)

2、編譯階段(.i-->.s)

3、彙編階段(.s-->.o)

4、鏈結階段(該程式的所有.o-->.exe)

1、c語言中部分內建巨集

2、巨集的功能

(1)、使用巨集定義常量

(2)、使用巨集重新命名運算子

(3)、使用巨集重新定義關鍵字的別名

(4)、巨集還能定義一段**片段

(5)、巨集還可以作為「編譯開關」

(6)、使用巨集完成算數表示式

三、預處理指令

1、#if 和 #elif

2、#ifdef

3、#ifndef

4、#if defined

5、#undef

當我們寫好乙個一段c語言的**並且按下編譯並執行這個按鈕時,它共經歷了這樣幾個過程:

該階段主要進行這幾個操作,巨集替換、標頭檔案的展開、預編譯指令的處理等。

編譯器將 .i 檔案翻譯成文字檔案 .s ,每條語句都以標準的文字格式確切描述一條低階機器語言指令;也是在這乙個階段進行語法語義的分析檢查。

彙編器將 .s 檔案翻譯成機器語言指令。把這些指令打包成可重定位目標檔案,即 .o 檔案。這裡 .o 是乙個二進位制檔案,前面兩個階段都還有字元。

將剛才生成的還有有標頭檔案庫中的 .o 檔案以某種方式合併到乙個 .o 檔案中(這個檔案是主函式所在的那個 .o 檔案),在經過一系列處理(如:合併段表,符號表的合併和符號表的重定位等)生成乙個 .exe 檔案。

巨集名功能

_ _file_ _

進行編譯的原始檔

_ _line_ _

檔案當前的行號

_ _date_ _

檔案被編譯的日期

_ _time_ _

檔案被編譯的時間

_ _stdc_ _ 

如果編譯器遵循ansi c,其值為1,否則未定義

注意,這裡是兩個下劃線,中間沒有空格。

//這些基本都是語言內建的巨集

//預定義符號是預處理的一部分,所以顯示的都是編譯時候的資訊而不是執行時候的資訊

printf("file:%s\n", __file__);//進行編譯的原始檔

printf("line:%d\n", __line__);//當前編譯的行號

printf("date:%s\n", __date__);//檔案被編譯的日期

printf("time:%s\n", __time__);//檔案被編譯的時間

//printf("stdc:%d\n", __stdc__);//編譯器是否遵循ansi c,如果遵循其值為1,否則不遵循,顯然vs不遵循

執行結果如下:

首先得知道巨集在實際的使用中是一種簡單的文字替換

例如:#define  size  10

int  a = size;

在預處理階段,將檔案中所有出現 size 的地方全部換成 10 ,於是int  a = size; 被替換為int  a = 10; 

正是因為巨集獨特的特點,所以我們可以使用巨集完成很多事情。

// 1. 使用巨集定義常量

#define size 10

// 2. 使用巨集給運算子重新命名

#define and &&

#define or ||

// 3. 使用巨集重新定義關鍵字的別名. 

#define uint unsigned int

在某些場景,我們可能會頻繁的使用一些**片段,例如:

實際開發中經常有這種需求:

如果程式執行成功,就繼續往下走如果程式執行失敗, 就結束程式

int main()

ret = enterroom();

if (ret == 0)

ret = startmatch();

if (ret == 0)

ret = acceptgame();

if (ret == 0)

return 0;

}

我們發現這個**中多次出現了

if (ret == 0)

為了使**更為簡潔,我們可以使用巨集定義:

// 5. 巨集還能定義一段**片段

#define check(ret) if (ret == 0)

int main()

注意  \  在c語言中還有換行的意思。

這裡和函式很像,但是這裡千萬不能寫成函式因為函式執行完之後只是退出它本身,但是我們這裡的需求是退出主函式。

某些巨集可以根據條件讓一些**能編譯或者不編譯。

_crt_secure_no_warnings

這個巨集想必使用vs 編譯器的同學們應該不陌生,沒有這個巨集的定義的時候, vs 就會多編譯一些對於 scanf 等函式安全檢查的邏輯;有這個巨集定義, 相關的檢查**就不被編譯了。

需要注意的是,這個巨集的宣告應該在 stdio.h 這個標頭檔案的上面,因為這個標頭檔案包含了 scanf 等函式的宣告。

比如我們想要算平方,就可以直接用巨集來定義:

#define square( x ) x * x
那這樣的定義方法可行嗎?

square( 5+1 )為多少?我們想要的結果是 6 的平方 36 ,但是巨集在編譯的過程中實際上是文字替換結果為 5+1*5+1,結果為11,所以我們需要給每乙個可能出現問題的地方加上括號。

#define square( x ) ((x) * (x))
這樣就萬無一失了。

**大概長這樣:

#if   整型常量表示式1

程式段1

#elif   整型常量表示式2

程式段2

#elif   整型常量表示式3

程式段3

#else

程式段4

#endif

這段**的意思是:「表示式1」的值為真(非0),就對「程式段1」進行編譯,否則就計算「表示式2」,結果為真的話就對「程式段2」進行編譯,為假的話就繼續往下匹配,直到遇到值為真的表示式,或者遇到 #else。這一點和 if else 非常類似。

**大概長這樣

#ifdef  巨集名

程式段1

#else

程式段2

#endif

它的意思是,如果當前的巨集已被定義過,則對「程式段1」進行編譯,否則對「程式段2」進行編譯。

**大概長這樣

#ifndef 巨集名

程式段1

#else

程式段2

#endif

與 #ifdef 相比,僅僅是將 #ifdef 改為了 #ifndef。它的意思是,如果當前的巨集未被定義,則對「程式段1」進行編譯,否則對「程式段2」進行編譯,這與 #ifdef 的功能正好相反。

需要注意的是,#if 後面跟的是「整型常量表示式」,而 #ifdef 和 #ifndef 後面跟的只能是乙個巨集名,不能是其他的。

**大概長這樣

#if defined 巨集名

**段#endif

判斷該巨集有沒有被定義,如果有則執行**段,否則跳過,可以在改變巨集的值之前進行判斷。

#undef 巨集名
這個指令用於移除巨集定義,當乙個現存的巨集需要被重新定義的時候,先移除它。

這個指令經常和上面的#if defined一起使用,我們可以看下面的例子:

#define b 20

#if defined b //判斷巨集b是否被定義

#undef b //若被定義,則撤銷定義

#endif

#define b 200 //改變巨集的值

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 被擴充套件...

C 預處理 巨集定義

開發乙個 c語言程式,讓它暫停 5 秒以後再輸出內容 helllo 並且要求跨平台,在 windows 和 linux 下 include 說明 在windows 作業系統和 linux作業系統下,生成原始碼不一樣 if win32 如果是windows平台,就執行 include elif lin...