【C语言进阶】预定义详解
預(yù)定義
- 一、預(yù)定義符號
- 二、#define
- 1.#define定義標識符
- 2.#define定義宏
- 3.#define替換規(guī)則
- 4.#和##
- 4.1 #號
- 4.2 ##號
- 三、函數(shù)與宏
- 1.代碼長度
- 2.執(zhí)行速度
- 3.操作符的優(yōu)先級
- 4.參數(shù)類型
- 5.調(diào)試
- 6.遞歸
- 7.帶有副作用的參數(shù)
- 四、條件編譯
一、預(yù)定義符號
預(yù)定義符號是C標準定義的宏定義符號
例如 FILE LINE DATE TIME STDC(如果編譯器遵循ASCI C就返回1,否則未定義。)
二、#define
1.#define定義標識符
語法:
define name stuff
(而這個stuff可以是不同的類型)
1.#define MAX 100
2.#define reg register(給register起一個短一點的名字)
3.#define arr “hello world.”
我們也可以利用這個來寫一個死循環(huán)
當然在寫代碼的時候會有這樣一個疑問,如果要寫的stuff過長怎么辦?這個時候我們可以分行寫,但是除了最后一行外,每一行都要加一個反斜杠(續(xù)航符)。
#define fad printf("name:%s\tage:%s\t \tele:%s\taddre:%s\t",\name,age\tele,addre)2.#define定義宏
#define機制包括了一個規(guī)定,允許把參數(shù)替換到文本中,這種實現(xiàn)通常稱為宏 (macro)或者定義宏(define macro)。
宏的申明方式
#define name(parament-list) stuff
其中parament-list是一個由逗號隔開的符號表,有可能會出現(xiàn)在后面的stuff中。
注意:參數(shù)列表的左括號必須與name緊鄰,不能有空格或者空白,否則會被認為是stuff的一部分。
在定義宏時要合理使用括號,防止運算符的優(yōu)先級問題
#define SQUARE(x) x*xint main() {int a = 4;printf("%d", SQUARE(a));return 0; }
但如果換成SQUARE(4+1)呢
我們可以看到結(jié)果是9,那是因為替換方式
#define SQUARE(x) 4+1*4+1
這樣就提醒我們在寫的時候最好帶上括號
#define SQUARE(x) (x)*(x)int main() {//int a = 4;printf("%d", SQUARE(4+1));return 0; }
但是這樣寫任然不夠嚴密,在有些時候還是會出現(xiàn)錯誤
將上述代碼中printf一部分換成
printf(“%f”, 1.0/SQUARE(4+1))
答案顯然不對,按上述的替換法方式就變成了
#define SQUARE(x) 1.0/(4+1)*(4+1)
那么這樣得出錯誤的結(jié)果也就不奇怪了
為了達到最初的目的,我們應(yīng)該這樣
當然還有一個特殊的地方就是不要在定義標識符或者定義宏時加上分號(;),這樣很容易在使用時出錯。
#define SQUARE(x) ((x)*(x));int main() {if(1)int a=SQUARE(4);printf("%d", a);return 0; }編譯預(yù)處理完,替換之后就變成了
if(1) >int a=((4)*(4));;if后面沒有大括號跟兩條語句是不對的
所以我們在定義標識符或者定義宏時不要加上分號,避免上述錯誤。
3.#define替換規(guī)則
在程序中擴展#define定義符號和宏時,需要涉及幾個步驟。
1.在調(diào)用宏時,首先多參數(shù)進行檢查,看看是否包括任何由#define定義的符號,如果是他們首先被替換。
2.替換文本隨后被插入到程序中原來文本的位置。對于宏,參數(shù)名被他們的只所替換。
3.最后,再次對結(jié)果文件進行掃描,看看它是否包含任何由#define定義的符號。如果是,就重復(fù)上述處理過程。
在這里有幾個需要注意的地方
1.宏參數(shù)和#define定義中可以出現(xiàn)其他#define定義的符號,但是對于宏,不能出現(xiàn)遞歸。
2.當預(yù)處理器搜索#define定義的符號的時候,字符串常量的內(nèi)容并不被搜索。
4.#和##
4.1 #號
如何把參數(shù)插入到字符串中?
首先我們要知道字符串是有自動連接的功能的的特點的。
比如:
而#號加在宏參數(shù)前時,可以將這個參數(shù)轉(zhuǎn)化為字符串。
可以看出只有a,b,c和%d,%f不同,這個時候可以用宏來寫
#define PRINT(x,format) printf("the value of "#x" is "format"\n",x) int main() {int a = 10;PRINT(a, "%d");int b = 20;PRINT(b, "%d");float c = 30.0f;PRINT(c, "%f");return 0; }4.2 ##號
##的作用是將兩個字符合成一個字符。
#define A(x,y) printf("%d\n",x##y) int main() {int ab = 20;A(a, b);return 0; }三、函數(shù)與宏
1.代碼長度
宏:每次使用時在編譯的預(yù)處理階段宏的代碼就會插入到程序中,如果宏的代碼量很大的話,那么整體的代碼量也會大大增加。
函數(shù):函數(shù)的代碼只有一份,每次調(diào)用都從這里調(diào)用。
2.執(zhí)行速度
宏比函數(shù)在速度和規(guī)模上都要更勝一籌。
3.操作符的優(yōu)先級
宏可能會帶來操作符的優(yōu)先級的問題。
比如上面已經(jīng)提過的:
執(zhí)行答案是9,但是我們的目的是算(4+1)*(4+1)
4.參數(shù)類型
宏:參數(shù)與類型無關(guān),只要參數(shù)合法就可以使用
函數(shù):只能在類型合適的表達式上使用,即參數(shù)必須聲明為特定的類型。
當然,因為函數(shù)與參數(shù)無關(guān)也就不夠嚴謹。
比如,對于比較大小,宏可以比較不同類型的大小(整形,浮點型等等)
5.調(diào)試
宏:由于宏是在編譯預(yù)處理直接替換的,所以無法調(diào)試
函數(shù):可以調(diào)試在vs2019下,按F10是逐過程,F11是逐語句(可以進入函數(shù)內(nèi)部調(diào)試)。
6.遞歸
宏是不能遞歸的
函數(shù)可以,比如用遞歸寫斐波那契數(shù)列
7.帶有副作用的參數(shù)
宏:宏參數(shù)可能被替換到多個位置,更容易出現(xiàn)問題
函數(shù):只在傳參時計算一次,結(jié)果不容易出錯
比如:
我們這里想要比較a++和b++ 的大小,也就是2和3的大小
我們想要的答案應(yīng)該是3才對
但事實上
這是因為經(jīng)過替換后
#define MAX(x,y) printf(“%d”,((++a)>(++b)?(++a):(++b)))
所以答案為4
這也是提醒我們在使用宏時不要使用帶有副作用的參數(shù)
四、條件編譯
在編譯一個程序的時候,可以用條件編譯來選擇將一條語句編譯或者放棄。
#include <stdio.h> #define __DEBUG__ int main() {int i = 0;int arr[10] = { 0 };for (i = 0; i < 10; i++){arr[i] = i; #ifdef __DEBUG__//判斷是否已經(jīng)定義,如果定義了就執(zhí)行下面的語句printf("%d\n", arr[i]); #endif }return 0; } 1. #if 常量表達式 //... #endif //常量表達式由預(yù)處理器求值。 如: #define __DEBUG__ 1 #if __DEBUG__ //.. #endif 2.多個分支的條件編譯 #if 常量表達式 //... #elif 常量表達式 //... #else //... #endif 3.判斷是否被定義 #if defined(symbol) //等于 #ifdef symbol #if !defined(symbol)// #ifndef symbol4.嵌套指令(與if嵌套相似) #if defined(OS_UNIX) #ifdef OPTION1 unix_version_option1(); #endif #ifdef OPTION2 unix_version_option2(); #endif #elif defined(OS_MSDOS) #ifdef OPTION2 msdos_version_option2(); #endif #endif總結(jié)
以上是生活随笔為你收集整理的【C语言进阶】预定义详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python模板注入_BUUCTF/护网
- 下一篇: 全球十大智能物流装备龙头企业