今天分享一點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...