目錄
一、用宏前須知-#define相關知識
????????大致結構:
?????????對預定義符號的補充:
二、用#define定義宏
????????什么是宏?
????????#define的替換規則:
三、常用的宏定義
1、宏定義常量
2、定義一個宏語句
3、宏定義函數
????????宏與函數的對比:
4、#和## 分別字符串化和將兩個符號連接成一個符號?
#字符串化
?##將兩個符號連接成一個符號
四、與宏相關的作用符號
1、換行符 '\'
2、取消宏定義#undef?
五、命名約定
一、用宏前須知-#define相關知識
????????大致結構:
#define ???name ???stuff自定義名 ???內容
????????栗子:
#define OP 256
#define YU "youarewelcome"
#define S(r) (r*r)
#define REG register ? ? ? ? ?//為 register這個關鍵字,創建一個簡短的名字
#define PRINT printf("file:%s line:%d\n", __FILE__, __LINE__)//__FILE__,__LINE__這是個啥?別急后面有補充!#include<stdio.h>
int main()
{printf("%d \n", OP);printf("%s \n",YU);printf("%d \n", S(6));PRINT;return 0;
}
? ? ? ? ?
?????????對預定義符號的補充:
__FILE__ //進行編譯的源文件
__LINE__ //文件當前的行號
__DATE__ //文件被編譯的日期
__TIME__ //文件被編譯的時間
__STDC__ //如果編譯器遵循ANSI C,其值為1,否則未定義
二、用#define定義宏
????????什么是宏?
????????宏可以看作為一些命令的集合。它是一種預處理器指令,在預編譯階段將宏名替換為后面的替換體。
????????而#define可以用來定義宏:
????????#define 機制包括了一個規定,允許把參數替換到文本中,這種實現通常稱為宏(macro)或定義宏(define macro)。
????????宏的聲明方式:
??#define name( parament-list ) stuff
//其中的 parament-list 是一個由逗號隔開的符號表,它們可能出現在stuff中
? ? ? ? 栗子:
????????實現一個開平方的宏? ? ? ??
#define SQ(x) x*xprintf("%d \n", SQ(7));
????????他的實際執行結構為7*7->即為49
????????還是用這個我們剛剛定義的宏
????????我們執行下面這段代碼:???????
int a=6;printf("%d \n", SQ(6+1));
????????他的實際執行結構為6+1*6+1->即為13
????????這說明了什么?這印證了上面所說的宏是把參數替換到文本中,也就是宏直接吧6+1替換掉了x直接帶入了后面的表達式當中了!
????????對此,根據我們原來的用意。這時我們可以用括號來解決這個問題:
#define SQ(x) (x)*(x)
????????這給了我們一個提醒:我們在用宏時最好多用括號,以此來避免不必要的錯誤!
再看個栗子:
#define DOUBLE(x) (x) + (x)
int a = 5;
printf("%d\n" ,10 * DOUBLE(a));
????????在這個例子中我們對這個宏使用了括號,乍一看這個例子輸出的值像是100
????????但是實際呢?上圖!
? ? ??
來看看實際它怎么執行的,它執行替換操作實際上為:
printf?("%d\n",10 *?(5) +?(5));
????????因此我們說定義宏要多用括號!
#define DOUBLE( x) ??( ( x ) + ( x ) )
????????改成這樣就能實現想要的效果啦!
????????#define的替換規則:
三、常用的宏定義
1、宏定義常量
?????????定義諸如:字符串、整形數、浮點型數等等的常量.
????????栗子:
#define AO 114514
#define NTR "我可太喜歡了"
#define KK 3.14
#include<stdio.h>
int main()
{printf("%d %s %f", AO, NTR, KK);return 0;
}
? ? ? ?
2、定義一個宏語句
????????栗子:
#include<stdio.h>
#define PFINT printf("hello world!\n");
int main()
{PFINT///預處理時會被替換為 printf("hello world!\n");return 0;
}
3、宏定義函數
????????宏可以接受參數,類似于真正的函數一樣。具體的接受參數方法與函數差不多,只不過不用指定函數類型,這也是宏定義函數的一個優勢!比如:當我定義了一個函數有時要傳整形,有時要傳浮點型,函數可能要根據類型來多定義幾個,而宏只需要一個就行了!
????????栗子1:
#define MAX(a, b) ((a)>(b)?(a):(b))
#include<stdio.h>int main()
{printf("%d", MAX(114, 514));return 0;
}
? ? ? ?
????????栗子2:
#define MALLOC(num, type)\
(type *)malloc(num * sizeof(type)) //這和\是干啥的?詳見地四大點\的作用
...
//使用
MALLOC(10, int);//類型作為參數
//預處理器替換之后:
(int *)malloc(10 * sizeof(int));
????????這個例子中,函數是做不到跟宏相同的效果的,所以說為啥有了函數我們還要定義宏呢?這個就是一個很明顯的例子。
????????宏與函數的對比:
4、#和## 分別字符串化和將兩個符號連接成一個符號?
#字符串化
????????這個很好理解看看例子就會了!
????????栗子:
#define STR(exp) printf("%s\n",#exp);
#include<stdio.h>
int main()
{STR(for fun)return 0;
}
? ? ??
?##將兩個符號連接成一個符號
????????##可以把位于它兩邊的符號合成一個符號。 它允許宏定義從分離的文本片段創建標識符。
????????栗子:
#include<stdio.h>
#define ADD_TO(num, value) num##valueint main()
{int a = ADD_TO(114, 514);printf("%d \n", a);return 0;
}
? ? ? ?
四、與宏相關的作用符號
1、換行符 '\'
????????在每行末尾(除了最后一行)加上"\",代表換行的意思。這個目的是為了不讓代碼冗余,如果代碼都擠在一段,代碼就不美觀,可讀性不好。
????????栗子:
#include<stdio.h>
#define PFINT printf("hello world!\n");\printf("goodbye world!\n");
#define NUM 1,\2,\3
int main()
{PFINTint x[] = { NUM };//->int x[] = { 1,2,3 };printf("%d %d %d \n", x[0], x[1], x[2]);return 0;
}
? ? ? ?
2、取消宏定義#undef?
????????這條指令用于移除一個宏定義。????????
#define SORT 1000
#undef SORT
????????在#undef之后SORT就相當于沒有定義,失效了。再使用則會報錯!
五、命名約定
? ? ? ? 細心的朋友可能發現了!我在定義宏時用的都是大寫的字母來作為它自定義的名字!
????????這是因為這有一個默認的命名約定:
????????一般來講函數的宏的使用語法很相似。所以語言本身沒法幫我們區分二者。
????????那我們平時的一個習慣是:
????????把宏名全部大寫
????????函數名不要全部大寫? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
???????感謝你耐心的看到這里?( ′・?・` )比心,如有哪里有錯誤請踢一腳作者o(╥﹏╥)o!