在將源代碼提交給編譯器之前,C語言預(yù)處理器將對(duì)源代碼做出一定修正。預(yù)處理器命令有很多如最常用的#include,#define命令.
預(yù)處理命令都是以#開頭,一般放在代碼的最左側(cè),通常定義的宏全部都是用大寫。
下面這一系列的指令都可以用來決定代碼的哪個(gè)部分應(yīng)該被編譯,這些指令包括:#if,#elif,#else,#ifdef,#else,#ifdef以及#ifndef。以#if開頭的語句塊必須以#endif結(jié)尾。
可以使用條件編譯來注釋代碼,例如
- #if 0
- /* comment ...
- */
- // code
- /* comment */
- #endif
以#if 表達(dá)式,如果表達(dá)式為假,那么這部分代碼就不會(huì)被編譯,為真才參與編譯。雖然你會(huì)說使用塊注釋也是可行的,但是可惜的是塊注視不支持嵌套,在某些環(huán)境下選擇#if 0確實(shí)是一個(gè)更好的選擇。測試代碼:
- #include<stdio.h>
- int main()
- {
- #if 0
- int a=10;
- #endif
- #if 1
- int a=11;
- #endif
- printf("a=%d\n",a);
- }
可以好似用#ifndef來避免頭文件被重復(fù)編譯:例如下面這段代碼:
- #ifndef _FILE_NAME_H_
- #define _FILE_NAME_H_
- /* code */
- #endif // #ifndef _FILE_NAME_H_
同樣的技術(shù)可以用來定義一些常量,如:
- #ifndef NULL
- #define NULL (void *)0
- #endif // #ifndef NULL
使用簡單的宏就不多說了,對(duì)于比較復(fù)雜的宏,常見的是使用類似于函數(shù)定義的宏,使用這種宏要特別注意宏的副作用。例如下面這段代碼:
#define MULT(x, y) x * y
int z = MULT(3 + 2, 4 + 2);
一般情況,要對(duì)所有的實(shí)參添加括號(hào),同時(shí)對(duì)宏體整體添加括號(hào)。
下面考察一種更加復(fù)雜的情況,交換兩個(gè)數(shù)的宏定義可以寫為:
- #define SWAP(a, b) a ^= b; b ^= a; a ^= b;
- int x = 10;
- int y = 5;
- // works OK
- SWAP(x, y);
- // What happens now?
- if(x < 0)
- SWAP(x, y);
對(duì)于第if語句會(huì)出現(xiàn)邏輯錯(cuò)誤,因?yàn)檫@個(gè)if語句只執(zhí)行第一個(gè)異或操作。嗯,或許你已經(jīng)想到了,加上大括號(hào),像下面這樣:
- #define SWAP(a, b) {a ^= b; b ^= a; a ^= b;}
然而,還是對(duì)于第二個(gè)if語句還是不正確,因?yàn)轭A(yù)處理器替換之后就出現(xiàn)了‘};’語法錯(cuò)誤。這里有一個(gè)技巧,正確的寫法如下:
- #define SWAP(a, b) do { a ^= b; b ^= a; a ^= b; } while ( 0 )
這下就可以了,這里沒有給實(shí)參加括號(hào)的原因是因?yàn)槲覀冎皇轻槍?duì)變量的交換,不考慮那些表達(dá)式交換。
如果宏體比較復(fù)雜的話,我們就需要使用\來分割宏體,示例代碼如下所示:
- #define SWAP(a, b) { \
- a ^= b; \
- b ^= a; \
- a ^= b; \
- }
有時(shí)候在宏體中我們需要連接兩個(gè)參數(shù)的名字這時(shí)候可以使用##:
- struct command
- {
- char *name;
- void (*function) ();
- };
- struct command commands[] =
- {
- { "quit", quit_command},
- { "help", help_command},
- {"run",run_help},
- {"open",open_help}
- };
在struct中顯然每個(gè)名字都重復(fù)了一遍,通過使用##可以減少重復(fù),方便維護(hù):
- #define COMMAND(NAME) { #NAME, NAME ## _command }
- struct command commands[] =
- {
- COMMAND (quit),
- COMMAND (help),
- COMMAND (run),
- COMMAND (open)
- };
有時(shí)候我們經(jīng)常需要將傳入到宏中的符號(hào)或者叫做參數(shù)轉(zhuǎn)換為文本形式,這樣對(duì)于打印這些符號(hào)的時(shí)候比較方便,在寫一些調(diào)試模塊的時(shí)候,經(jīng)常會(huì)遇到這樣的需求,實(shí)現(xiàn)這個(gè)過程的語法很簡單,只需要在符號(hào)前面添加一個(gè)‘#’就可以了。例如下面這段代碼:
- #define PRINT_TOKEN(token) printf(#token " is %d", token)
- PRINT_TOKEN(foo);
PRINT_TOKEN(foo);將被擴(kuò)展 為printf("<foo>" " is %d" <foo>)
新版本的C語言支持將多個(gè)使用雙引號(hào)括起來的字符串練成一個(gè)整體的字符串。
下面為測試代碼:
- #include<stdio.h>
- #define PRINT_TOKEN(token) printf(#token " is %d\n",token);
- int main()
- {
- int x=10,y=20;
- PRINT_TOKEN(x+y);
- }
聯(lián)系客服