一文帶你搞懂C語(yǔ)言預(yù)處理宏定義
預(yù)定義符號(hào)
這些預(yù)定義符號(hào)都是語(yǔ)言?xún)?nèi)置的
__FILE__ //進(jìn)行編譯的源文件 __LINE__ //文件當(dāng)前的行號(hào) __DATE__ //文件被編譯的日期 __TIME__ //文件被編譯的時(shí)間 __STDC__ //如果編譯器遵循ANSI C,其值為1,否則未定義
VS環(huán)境下未定義__STDC__ ,說(shuō)明Visual Studio并未完全遵循ANSI C。
#define
#define 定義標(biāo)識(shí)符
#define name stuff //名稱(chēng);內(nèi)容
#define MAX 1000 #define reg register //為 register這個(gè)關(guān)鍵字,創(chuàng)建一個(gè)簡(jiǎn)短的名字 #define do_forever for(;;) //用更形象的符號(hào)來(lái)替換一種實(shí)現(xiàn) #define CASE break;case //在寫(xiě)case語(yǔ)句的時(shí)候自動(dòng)把 break寫(xiě)上。 // 如果定義的 stuff過(guò)長(zhǎng),可以分成幾行寫(xiě),除了最后一行外,每行的后面都加一個(gè)反斜杠(續(xù)行符)。 #define DEBUG_PRINT printf("file:%s\tline:%d\t \ date:%s\ttime:%s\n" ,\ __FILE__,__LINE__ , \ __DATE__,__TIME__ ) int main() { printf("%d\n", MAX); printf("%s\n", STR); do_forever; //執(zhí)行到這里會(huì)死循環(huán) return 0; }
在define進(jìn)行定義時(shí),最好不要在后面加上分號(hào) ;
,替換時(shí)也會(huì)將分號(hào)替換,容易導(dǎo)致問(wèn)題。
#define 1000; int max = 0; if (3 > 1) max = MAX; else max = 0; //報(bào)錯(cuò)
#define 定義宏
#define 機(jī)制包括了一個(gè)規(guī)定,允許把參數(shù)替換到文本中,這種實(shí)現(xiàn)通常稱(chēng)為宏(macro)或定義宏(define macro)
#define name( parament-list ) stuff
其中的 parament-list 是一個(gè)由逗號(hào)隔開(kāi)的符號(hào)表,它們可能出現(xiàn)在stuff中。
//int Max(int x, int y) { // return (x > y ? x : y); //} //若采用宏定義 #define Max(x,y) (x>y?x:y) int main() { int a = 10; int b = 5; int max = Max(a, b); printf("%d\n", max); return 0; }
最終得到較大值10。找到了宏的標(biāo)識(shí),直接進(jìn)行符號(hào)替換。
- 參數(shù)列表的左括號(hào)必須與name緊鄰。
- 如果兩者之間有任何空白存在,參數(shù)列表就會(huì)被解釋為stuff的一部分
例如:
#define SQUARE(x) x*x int main() { printf("%d\n", SQUARE(5)); printf("%d\n", SQUARE(5 + 1)); //宏的參數(shù)是完全替換的,相當(dāng)于 5 + 1 * 5 + 1 結(jié)果為11 return 0; }
做改進(jìn):
#define SQUARE(x) (x)*(x) //這樣就不容易出錯(cuò) //最好最外層也加上括號(hào)
考慮如下計(jì)算:
#define Double(x) (x)+(x) int main() { int a = 5; printf("%d\n", (10 * Double(a))); //這里相當(dāng)于 10 * (5) + (5) 結(jié)果為55 return 0; }
在宏替換內(nèi)容上加上括號(hào)以保證得到預(yù)期的結(jié)果。
#define Double(x) ((x)+(x))
所以用于對(duì)數(shù)值表達(dá)式進(jìn)行求值的宏定義都應(yīng)該用這種方式加上括號(hào),避免在使用宏時(shí)由于參數(shù)中的操作符或鄰近操作符之間不可預(yù)料的相互作用。
替換規(guī)則
在程序中擴(kuò)展#define定義符號(hào)和宏時(shí),需要涉及幾個(gè)步驟。
- 在調(diào)用宏時(shí),首先對(duì)參數(shù)進(jìn)行檢查,看看是否包含任何由#define定義的符號(hào)。如果是,它們首先被替換。
- 替換文本隨后插入到程序中原來(lái)文本的位置。對(duì)于宏,參數(shù)名被他們的值所替換。
- 最后,再次對(duì)結(jié)果文件進(jìn)行掃描,看看它是否包含任何由#define定義的符號(hào)。如果是,就重復(fù)上述處理過(guò)程。
注意:
宏參數(shù)和#define 定義中可以出現(xiàn)其他#define定義的符號(hào)。但是對(duì)于宏,不能出現(xiàn)遞歸。
當(dāng)預(yù)處理器搜索#define定義的符號(hào)的時(shí)候,字符串常量的內(nèi)容并不被搜索。
# 和##
如何把參數(shù)插入到字符串中?
#define PRINT(FORMAT, VALUE) printf("the value of " #VALUE " is "FORMAT "\n", VALUE) //這里#可以把其后面的參數(shù)替換為字符串嵌入 int main() { printf("hello world\n"); printf("hello ""world\n"); //天然合為一個(gè)字符串(發(fā)現(xiàn)字符串是有自動(dòng)連接的特點(diǎn)的) int a = 100; printf("The value a is %d\n", a); int b = 20; printf("The value b is %d\n", b); //那么考慮能否將同一個(gè)功能的打印操作合并 PRINT("%d", a); //這里只有當(dāng)字符串作為宏參數(shù)的時(shí)候才可以把字符串放在字符串中 /*代碼中的 #VALUE 會(huì)預(yù)處理器處理為: "VALUE" .*/ return 0; }
把宏對(duì)應(yīng)的參數(shù)替換為字符串
##的作用
將分離的片段合成為一個(gè)符號(hào)
#define CAT(A,B) A##B //把A和B組合成一個(gè)符號(hào) int main() { int Windows11 = 2022; printf("%d\n", CAT(Windows, 11)); }
帶副作用的宏參數(shù)
當(dāng)宏參數(shù)在宏的定義中出現(xiàn)超過(guò)一次的時(shí)候,如果參數(shù)帶有副作用,那么你在使用這個(gè)宏的時(shí)候就可能出現(xiàn)危險(xiǎn),導(dǎo)致不可預(yù)測(cè)的后果。副作用就是表達(dá)式求值的時(shí)候出現(xiàn)的永久性效果。
x+1;//不帶副作用 x++;//帶有副作用
考慮宏:
//考慮宏的副作用 #define MAX(a, b) ( (a) > (b) ? (a) : (b) ) int main() { int x = 5; int y = 8; int z = MAX(x++, y++); printf("x=%d y=%d z=%d\n", x, y, z); //z = ((x++) > (y++) ? (x++) : (y++)); x = 6 y = 10 z = 9 }
到此這篇關(guān)于一文帶你搞懂C語(yǔ)言預(yù)處理宏定義的文章就介紹到這了,更多相關(guān)C語(yǔ)言預(yù)處理宏定義內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
iostream與iostream.h的區(qū)別詳細(xì)解析
以下是對(duì)C++中iostream與iostream.h的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下2013-09-09C++ 中的INT_MAX,INT_MIN數(shù)值大小操作
這篇文章主要介紹了C++ 中的INT_MAX,INT_MIN數(shù)值大小操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03用C語(yǔ)言求解一元二次方程的簡(jiǎn)單實(shí)現(xiàn)
這篇文章主要介紹了用C語(yǔ)言求解一元二次方程的簡(jiǎn)單實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11Qt利用QDrag實(shí)現(xiàn)拖拽拼圖功能詳解
QDrag類(lèi)為MIME-based拖拽數(shù)據(jù)轉(zhuǎn)換提供支持。本文為大家主要介紹如何利用QDrag類(lèi)實(shí)現(xiàn)拖拽拼圖功能。左邊是打散的圖,拖動(dòng)到右邊進(jìn)行復(fù)現(xiàn),此外程序還支持手動(dòng)拖入原圖片,感興趣的可以了解一下2022-07-07如何通過(guò)wrap malloc定位C/C++的內(nèi)存泄漏問(wèn)題
用C/C++開(kāi)發(fā)的程序執(zhí)行效率很高,但卻經(jīng)常受到內(nèi)存泄漏的困擾。本文提供一種通過(guò)wrap malloc查找memory leak的思路。2021-05-05QT+OpenGL實(shí)現(xiàn)簡(jiǎn)單圖形的繪制
這篇文章主要為大家詳細(xì)介紹了如何利用QT和OpenGL實(shí)現(xiàn)簡(jiǎn)單圖形的繪制,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2022-12-12