C的預(yù)處理,是在程序被編譯之前執(zhí)行的,執(zhí)行的操作有:將其他文件包含到正在被編譯的文件中來(lái),定義符號(hào)常量(symbol constant)和宏(macro),程序代碼的條件編譯(conditional compilation)和有條件地執(zhí)行預(yù)處理命令(conditional execution of PReprocessor directive)。預(yù)處理命令都是以#開(kāi)頭,同一行中只有空格和注釋會(huì)出現(xiàn)在預(yù)處理命令之前。
include預(yù)處理命令用于將指定文件的一個(gè)副本包含到該命令所在的位置上。有如下兩種形式:
#include <filename>#include "filename"差別在于查找欲包含文件的起始位置不同。 用引號(hào)括起來(lái),則預(yù)處理器從待編譯文件所在的目錄里開(kāi)始查找欲包含的文件(當(dāng)然也會(huì)在其他位置查找)。這種方法通常用來(lái)包含程序員定義的頭文件。 用尖括號(hào)括起來(lái),則預(yù)處理器按照一種依賴于系統(tǒng)實(shí)現(xiàn)的方式,通常在預(yù)先指定的編譯器和系統(tǒng)目錄中開(kāi)始查找。通常用來(lái)包含標(biāo)準(zhǔn)函數(shù)庫(kù)的頭文件。 被不同源程序所公用的聲明通常被編輯成一個(gè)頭文件,然后將其分別包含到各個(gè)源程序中。
#define命令的格式如下:
#define identifier replacement-text在這一行出現(xiàn)之后,除了字符串文本外,其后出現(xiàn)的所有identifier(標(biāo)識(shí)符)都會(huì)在程序編譯前被自動(dòng)地替換成replacement-text(替換文本)。在符號(hào)常量(標(biāo)識(shí)符)右邊的所有內(nèi)容都會(huì)用來(lái)替換這個(gè)符號(hào)常量。例如:
#define PI = 3.1415將會(huì)使程序中所有的PI都被“= 3.1415”所替換
宏也是預(yù)處理命令提供的一種標(biāo)識(shí)符。與符號(hào)常量一樣,程序中所有的宏標(biāo)識(shí)符(macro-identifier)也要在編譯前用其對(duì)應(yīng)的替換文本來(lái)替換。宏的定義可以帶實(shí)參,也可以不帶。不帶實(shí)參的宏在處理上和符號(hào)常量沒(méi)有差別。對(duì)于帶實(shí)參的宏,實(shí)參將會(huì)被代入到替換文本中,這樣宏就被展開(kāi)了(宏標(biāo)識(shí)符和實(shí)參列表都被替換)。如下:
#define CIRCLE_AREA(x) ((PI)*(x)*(x))此后凡是出現(xiàn)CIRCLE_AREA(y)的地方,y的值都會(huì)被代入到替換文本中x的位置,符號(hào)常量PI也會(huì)被它自己的值替換,然后宏就展開(kāi)了。如:
area = CIRCLE_AREA(4);被展開(kāi)為:
area = ((3.1415)*(4)*(4));當(dāng)宏實(shí)參是一個(gè)表達(dá)式時(shí),替換文本中將x括起來(lái)的圓括號(hào)可以保證計(jì)算順序的正確性。如:
area = CIRCLE_AREA(4 + c);被展開(kāi)為:
area = ((3.1415)*(4 + c)*(4 + c));也可以將宏定義成一個(gè)函數(shù),但是函數(shù)會(huì)帶來(lái)調(diào)用函數(shù)的開(kāi)銷。宏的優(yōu)點(diǎn)是直接將代碼插入到程序中,避免了調(diào)用函數(shù)的開(kāi)銷,而且還使程序仍然保持良好的可讀性。而缺點(diǎn)是需要對(duì)其實(shí)參求兩次值。 宏有時(shí)被用來(lái)以內(nèi)聯(lián)代碼替換一個(gè)函數(shù),從而消除了函數(shù)調(diào)用的開(kāi)銷,但是目前優(yōu)化的編譯器常常會(huì)替代程序員將其內(nèi)聯(lián)。 標(biāo)準(zhǔn)庫(kù)中函數(shù)有時(shí)也被定義成一個(gè)基于其他庫(kù)函數(shù)的宏。如:
#define getchar() getc(stdin)一般在stdio.h中都存在。
宏或者符號(hào)常量的替換文本是在#define預(yù)處理命令這一行中位于標(biāo)識(shí)符之后的所有文本。如果這一行剩余空間不夠?qū)懴潞昊蛘叻?hào)常量的替換文本,則必須要在行的末尾加上一個(gè)反斜杠(/),表示下一行繼續(xù)是替換文本。 符號(hào)常量和宏可以用#undef預(yù)處理命令來(lái)撤銷。該命令將撤銷符號(hào)常量和宏的定義,所以宏或者符號(hào)常量的作用域是從它們的定義開(kāi)始到被它們#undef命令撤銷為止或者文件末尾為止。一旦被撤銷,宏名或者符號(hào)常量名可以用#define預(yù)處理命令來(lái)重新定義。
條件編譯使用戶能夠控制預(yù)處理命令的執(zhí)行以及對(duì)程序代碼的編譯。每一個(gè)條件預(yù)處理命令都要計(jì)算一個(gè)整型表達(dá)式的值,但是強(qiáng)制類型轉(zhuǎn)換,sizeof表達(dá)式以及枚舉常量的值不能在預(yù)處理命令中計(jì)算。使用如下:
#if 0 code prevented from compiling#endif將0改為1就可以讓上述部分代碼參與編譯。 條件預(yù)處理命令結(jié)構(gòu)非常類似于if選擇語(yǔ)句,每個(gè)#if都使用#endif來(lái)結(jié)束。對(duì)于多分支的條件預(yù)處理結(jié)構(gòu),需要使用命令#elif(等價(jià)于if條件語(yǔ)句中的else if)和#else(等價(jià)于if條件語(yǔ)句中的else)。這些命令通常被用來(lái)防止頭文件被多次包含到同一個(gè)源文件中。 預(yù)處理命令#ifdef和#ifndef是#if defined(name)和#if !defined(name)的縮寫形式。使用如下:
#if !defined(MY_CONSTANT) #define MY_CONSTANT 0#endif首先判斷MY_CONSTANT是否被定義。如果定義了,則表達(dá)式defined(MY_CONSTANT)的值為1,否則為0,定義MY_CONSTANT為0。 條件編譯一般用于程序調(diào)試,如果沒(méi)有調(diào)試器,一般使用printf命令打印變量的值以驗(yàn)證控制的流向。對(duì)于這樣的printf可以用條件預(yù)處理命令封裝起來(lái)以便使其僅在程序調(diào)試過(guò)程中參加編譯。如下:
#ifdef DEBUG printf("Variable x = %d/n", x);#endif只有在該命令之前定義了符號(hào)常量DEBUG,上面的printf才會(huì)參加編譯。
預(yù)處理命令#error打印出包含命令中指定tokens(標(biāo)記)的信息,信息的具體內(nèi)容和系統(tǒng)的實(shí)現(xiàn)有關(guān)。標(biāo)記是用空格分隔的一個(gè)字符序列。使用如下:
#error 1 - Out of range error包含了6個(gè)標(biāo)記,某些系統(tǒng)執(zhí)行該條指令時(shí),命令中的標(biāo)記將被作為出錯(cuò)信息顯示出來(lái),然后終止預(yù)處理,并停止程序編譯。
#pragma tokens執(zhí)行一個(gè)系統(tǒng)實(shí)現(xiàn)中已經(jīng)定義好了的操作,不能被系統(tǒng)識(shí)別出來(lái)的將被忽略掉。
#和##運(yùn)算符僅在標(biāo)準(zhǔn)C中有效。#將替換文本中的標(biāo)記轉(zhuǎn)換成一個(gè)用引號(hào)引起來(lái)的字符串。#必須用在一個(gè)帶有實(shí)參的宏當(dāng)中,因?yàn)?的操作數(shù)就是宏的實(shí)參。使用如下:
#define HELLO(x) printf("Hello, " #x "/n");當(dāng)程序中出現(xiàn)了HELLO(John),將被替換成:
printf("Hello, John/n");##用于將兩個(gè)標(biāo)記拼接在一起。使用如下:
#define TOKENCONCAT(x, y) x ## y若程序中出現(xiàn)TOKENCONCAT(O,K),將會(huì)被OK替換。##操作符必須要有兩個(gè)操作數(shù)。
#line使在它之后的后繼程序代碼行,按照命令中給定的整型常數(shù)值,重新編排序號(hào)。如:
#line 100使下一行程序代碼的行號(hào)從100開(kāi)始。同時(shí),#line命令中還可以包含文件名,如下:
#line 100 "file1.c"表示從下一行程序代碼開(kāi)始 ,后繼代碼行的行號(hào)從100開(kāi)始編號(hào)。同時(shí),任何編譯器消息采用的文件名都是file1.c。該命令有助于讓語(yǔ)法錯(cuò)誤和編譯器警告產(chǎn)生的信息更好理解。這些符號(hào)并不出先在源程序文件中。
以下標(biāo)識(shí)符和defined標(biāo)識(shí)符(判斷是否標(biāo)識(shí)符定義過(guò))都不可用于#define和#undef命令。
_LINE_ 源程序文件中當(dāng)前代碼行號(hào)(整型常量)_FILE_ 假定的源文件名(一個(gè)字符串)_DATE_ 編譯源文件的日期(如“Jan 19 2002”)_TIME_ 編譯源文件的時(shí)間(格式為“時(shí) 分 秒”的字符串文本)_STDC_ 如果編譯器支持標(biāo)準(zhǔn)C,則值為1宏assert在頭文件assert.h中定義,用于測(cè)試一個(gè)表達(dá)式的值,如果表達(dá)式為假(0),則assert打印出錯(cuò)信息,并調(diào)用函數(shù)abort(stdlib.h中定義)來(lái)結(jié)束程序執(zhí)行。是一個(gè)用于測(cè)試變量的值是否正確的的調(diào)試工具。使用如下:
assert(x <= 10);若x大于10,則包含有行號(hào)和文件名的出錯(cuò)信息就會(huì)被打印出來(lái),然后程序終止。 如果定義了符號(hào)常量NDEBUG,則其后所有的斷言都將被忽略掉。若想忽略斷言,只需在程序開(kāi)始時(shí)插入一行:
#define NDEBUG新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注