C預(yù)處理器在預(yù)處理器在源代碼編譯之前怕膛,對(duì)其進(jìn)行一些文本性質(zhì)的操作,它的主要任務(wù)包括:
- 刪除注釋焕盟;
- 插入被#include指令所包含的的文件內(nèi)容铝阐;
- 定義和替換由#define指令定義的符號(hào);
- 確定代碼的部分內(nèi)容是否應(yīng)該根據(jù)一些條件編譯指令進(jìn)行編譯删壮;
預(yù)定義符號(hào)
下表總結(jié)了預(yù)處理器定義的符號(hào)贪绘,它們的值是字符串常量或是十進(jìn)制數(shù)字常量。
符號(hào) | 樣例值 | 含義 |
---|---|---|
FILE | "name.c" | 進(jìn)行編譯的文件名 |
LINE | 25 | 文件的當(dāng)前行號(hào) |
DATE | "jan 31 1997" | 文件被編譯的日期 |
TIME | "18:04:30" | 文件被編譯的時(shí)間 |
define
#define的一般形式如下:
#define name staff
有了這條指令央碟,每當(dāng)有符號(hào)name出現(xiàn)在這條指令后面時(shí)税灌,預(yù)處理器就會(huì)把它替換成staff.
替換文本并不僅限于數(shù)值字面常量。#define指令亿虽,可以把任何文本替換到程序中菱涤,下面有幾個(gè)例子。
#define reg register
#define do_forever for(;;)
#define CASE break;case
如果定義中的staff非常長(zhǎng)洛勉,它可以分成幾行粘秆,除了最后一行之外,每行都要加上一個(gè)反斜杠(\),如下面的例子:
#define DEBUG_PRINT printf("File % line %d:"\
"x=%d,y=%d,z=%d",\
__FILE__,__LINE__,\
x,y,z)
宏
#define機(jī)制包括了一個(gè)規(guī)定收毫,允許把參數(shù)替換到文本中攻走,這種實(shí)現(xiàn)通常稱為宏或定義宏殷勘,下面是宏的定義方式:
#define name(parameter_list) stuff
- 參數(shù)列表的左括號(hào)必須與name緊鄰,如果兩者之間出現(xiàn)空白昔搂,列表參數(shù)就會(huì)被解釋為stuff的一部分玲销。
- stuff每個(gè)參數(shù)加上括號(hào)以及整個(gè)stuff加上括號(hào)避免引起歧義,如下:
define DOUBLE(x) ((x)+(x))
函數(shù)與宏
宏的優(yōu)點(diǎn)或缺點(diǎn):
優(yōu)點(diǎn):
- 使用宏比使用函數(shù)在程序的規(guī)模和速度方面更勝一籌摘符;
- 宏與類型無(wú)關(guān)贤斜;
- 使用宏可以完成函數(shù)無(wú)法完成的操作;
缺點(diǎn):
- 每次使用宏逛裤,一份宏定義的代碼的拷貝都將插入到程序中——除非宏非常短瘩绒,否則使用宏大幅度增加程序的長(zhǎng)度;
/*宏與類型無(wú)關(guān)的例子*/
#define MAX(a,b) ((a) > (b) ? (a) : (b))
/*使用宏可以處理函數(shù)無(wú)法處理的例子*/
#define MALLOC(n,type) ((type*)malloc((n) * sizeof(typpe)))
undef
這條指令用于移除一個(gè)宏别凹,使用形式如下:
#undef name
如果一個(gè)現(xiàn)存的名字需要被重新定義草讶,那么它的就定義必須使用#undef移除洽糟。
條件編譯
在編譯的過(guò)程中炉菲,如果我們可以選擇某條語(yǔ)句或某組語(yǔ)句進(jìn)行翻譯或忽略將會(huì)很方便,條件編譯能夠很好的滿足上述假想坤溃,有兩種條件編譯的形式:
- 第一種形式:
#if constant-expression
statements
#endif
- 第二種形式:
#if constant-expression
statements
#elif constant-expression
other statements...
#else
other statements
#endif
- constant-expression 常量表達(dá)式(字面值常量或是#define定義的符號(hào))拍霜,由預(yù)處理器進(jìn)行求值;
- 如果constant-expression為真薪介,那么statemens被正常編譯祠饺,否則被忽略;
- elif的個(gè)數(shù)沒(méi)有限制汁政,每個(gè)constant-expression 只有當(dāng)前面所有的常量表達(dá)式的值都為假時(shí)才會(huì)被編譯道偷,#else子句中的語(yǔ)句只有當(dāng)前面的所有常量表達(dá)式的值都為假時(shí)才被編譯,其它情況下都被忽略记劈。
是否被定義
測(cè)試一個(gè)符號(hào)是否被定義也是可能的勺鸦,它的使用形式如下:
- 第一組等價(jià)形式:
#if defined(symbol)
#ifdef symbol
- 第二組等價(jià)形式:
# if !defined(symbol)
#ifndef symbol
嵌套指令
條件編譯的指令可以相互嵌套,如下:
#if defined(OS_UNIX)
#ifdef OPTION1
unix_version_of_option1();
#endif
#ifdef OPTION2
unix_version_of_option2();
#endif
#elif defined(OS_MDOS)
#ifdef OPTION2
msdos_version_of_option2();
#endif
#endif
文件包含
#include指令使另一個(gè)文件的內(nèi)容被編譯目木,這種替換的方式很簡(jiǎn)單:預(yù)處理器首先將這些指令刪除换途,并用包含的內(nèi)容取而代之,一個(gè)頭文件被包含了多少次就實(shí)際被編譯了多少次刽射。
函數(shù)庫(kù)文件的包含
函數(shù)庫(kù)文件的包含使用下面的語(yǔ)法:
#include <filename>
本地文件包含
本地庫(kù)文件的包含使用下面的語(yǔ)法:
#include "filename"
處理本地頭文件的一種策略就是在源文件所在的當(dāng)前目錄進(jìn)行查找军拟,如果該頭文件未找到,編譯器就像查找函數(shù)庫(kù)頭文件一樣在標(biāo)準(zhǔn)位置查找本地頭文件誓禁。
嵌套文件包含
多重包含在絕大多數(shù)情況下出現(xiàn)于大型程序中懈息,他往往需要使用很多頭文件,避免多重包含可以使用下面這種編寫(xiě)方式來(lái)編寫(xiě)頭文件
#ifndef _HEADERNAME_H
#define _HEADERNAME_H
/*
*All the stuff that you want in the header file
*/
#endif
當(dāng)頭文件第一次被包含時(shí)摹恰,它正常處理辫继,再次包含阁最,它的所有內(nèi)容被忽略。