1.預(yù)定義符號
? ? 下表總結(jié)由預(yù)處理器定義的符號。他們的值或者是字符串常量,或者是十進制數(shù)字常量。__FILE__和__LINE__在確認調(diào)試輸出的來源方面很有用處。__DATE__和__TIME__常用語在被編譯函數(shù)中加入版本信息。__STDC__用于那些在ANSI環(huán)境和非ANSI環(huán)境必須進行編譯的程序中結(jié)合條件編譯。
__FILE__"name.c"進行編譯的源文件名__LINE__?25文件當(dāng)前行的行號__DATE__"JAN 31 1997"文件被編譯的日期__TIME__"16:01:22"文件被編譯的時間__STDC__1如果編譯器遵循ANSIC,其值就為1,否則為定義
2.#define
#define?name?stuff #define?REG? register #define?DO_FOREVER? for(;;) #define?CASE? break;case? #define?DEBUG_PRINT printf("File?%s?line?%d:"? "x=%d,?y=%d,?z=%d", __FILE__,?__LINE__,? x,?y,?z?)
2.1宏
? ? #define機制包括了一個規(guī)定,運行把參數(shù)替換到文本中,這種實現(xiàn)通常稱為宏(macro)或定義宏
#define?name(?parameter-list?)?stuff
? ? 注意一下的差異:
#define?SQUARE(x)?????x*x #define?SQUARE(x)?????(x)*(x) #define?DOUBLE(x)?????(x)+(x) #define?DOUBLE(x)?????((x)+(x))
? ? 所有對于數(shù)值表達式進行求值的宏定義都應(yīng)該用這種方式加深括號,避免在使用宏時,由于參數(shù)中的操作符或鄰近的操作符之間不可預(yù)料的相互作用。
2.2#define替換
? ? 當(dāng)預(yù)處理器搜索#define定義的符號時,字符串常量的內(nèi)容并不進行檢查。如果想把宏參數(shù)插入到字符串常量中,可以使用兩種技巧。首先,鄰近字符串自動連接的特性可以把一個字符串分成幾段,每段實際上都是一個宏參數(shù)。如:
#define?PRINT1(?FORMAT,?VALUE)?printf("The?value?is?"FORMAT"n"?,?VALUE) PRINT1("%d",?x?+?3);
輸出結(jié)果為:
The?value?is?3
? ? 第2個技巧使用預(yù)處理器把一個宏參數(shù)轉(zhuǎn)換成字符串。#argument這種結(jié)構(gòu)被預(yù)處理器翻譯為"argument"。如下:
#define?PRINT1(?FORMAT,?VALUE)?printf("The?value?of?"#VALUE"?is?"FORMAT"n"?,?VALUE) PRINT1("%d",?x?+?3);
輸出結(jié)果為:
The?value?of?x?+?3?is?3
? ? ##結(jié)構(gòu)則執(zhí)行一種不同的任務(wù)。它把位于它兩邊的符號連成一個符號。它允許宏定義從分離的文本片段中創(chuàng)建標(biāo)識符。下面這段代碼使用這種連接把一個值添加到幾個變量之一:
#define?ADD_TO_SUM(?sum_number,?value)? sum?##?sum_number?+=?value ... ADD_TO_SUM(?5,?25?);
? ? 最后一條語句把值25添加到sum5變量中。注意這種連接必須產(chǎn)生一個合法的標(biāo)識符。
2.3宏與函數(shù)
代碼長度
每次使用時,宏代碼都將被插入程序中。除了非常小的宏之外,程序的長度將大幅度增加
函數(shù)代碼只出現(xiàn)于一個地方;每次調(diào)用這個函數(shù)時,都調(diào)用那個地方的同一份代碼
執(zhí)行速度更快存在函數(shù)調(diào)用/返回的額外開銷操作符優(yōu)先級
宏參數(shù)的求值是在所有周圍表達式的上下文環(huán)境里,除非它們加上括號,否則鄰近操作符的優(yōu)先級可能會產(chǎn)生不可預(yù)料的后果。
函數(shù)的參數(shù)只在函數(shù)調(diào)用時求值一次,它的結(jié)果值傳遞給函數(shù)。表達式的求值結(jié)果更易預(yù)測。
參數(shù)求值
參數(shù)每次用于宏定義時,它們都將重新求值。由于多次求值,具有副作用的參數(shù)可能會產(chǎn)生不可預(yù)料的結(jié)果
參數(shù)在函數(shù)被調(diào)用前只求值一次。在函數(shù)中多次使用參數(shù)并不會導(dǎo)致多種求值過程。參數(shù)的副作用并不會造成任何特殊的問題。
參數(shù)類型
宏和類型無關(guān)。只要對參數(shù)的操作是合法的,它可以使用于任何參數(shù)類型。
函數(shù)的參數(shù)是與類型有關(guān)的。如果參數(shù)的類型不同,就需要使用不同的函數(shù),即使它們執(zhí)行的任務(wù)是相同的
? ? 宏較函數(shù)的不利之處在于每次使用宏時,一份宏定義代碼的拷貝都將插入到程序中。除非宏特別短,否則使用宏可能會大幅度增加程序長度。
? ? 宏較函數(shù)的優(yōu)點有:
#define?MAX(?x,?y)?(?(a)>(b)???(a)?:?(b))
? ? ?1.用于調(diào)用和從函數(shù)返回的代碼很可能比實際執(zhí)行這個小型計算工作的代碼更多,即使用宏比使用函數(shù)在程序的規(guī)模和速度方面都更勝一籌。
? ? ?2.函數(shù)的參數(shù)必須聲明為一種特定的類型,所以它只能在類型合適的表達式上使用。而上面代碼的宏可以對int、long、float、double以及其他任何可以使用>操作符比較值大小的類型。即宏與類型無關(guān)。
#define?MALLOC(?n,?type?)?((type?*)malloc((n)?*?sizeof(?type?))) pi?=?MALLOC(?5,?int?); pi?=?(int?*)malloc(?5?*?sizeof(?int?));
? ? ?3.一些任務(wù)無法通過函數(shù)實現(xiàn)。上述代碼第1行的宏的第2個參數(shù)是一種類型,無法作為函數(shù)參數(shù)進行傳遞。第2行代碼預(yù)處理后與第3含代碼沒有區(qū)別。
2.4.宏的副作用
? ? 如果宏參數(shù)在宏定義中出現(xiàn)次數(shù)超過一次,倘若該參數(shù)具有副作用(如調(diào)用時參數(shù)是x++或者getchar()等),那么使用宏可能導(dǎo)致不可預(yù)料的結(jié)果。
2.5命名約定
? ? 常見約定為宏名字全部大寫。
2.6#undef
#undef?name
? ? 這條預(yù)處理指令用于移除一個宏定義。如果一個現(xiàn)存的名字需要重新被定義,那么它的舊定義首先必須使用#undef擦除。
3.條件編譯
#if?constant-expression statements #elif?constant-expression other?statements #elif?constant-expression other?statements ... #endif
? ? 其中,常量表達式(constant-expression)由預(yù)處理器進行求值,如果值為非0,那么statements被正常編譯,否則預(yù)處理器就忽視它們。
#if?defined(symbol) #ifdef?symbol #if?!defined(symbol) #ifndef?symbol
? ? 對應(yīng)的兩條語句等價,但#if形式功能更強,因為常量表達式可能包含額外的條件。
#if? defined(?OS_UNIX?) #ifdef?OPTION1 unix_version_of_option1(); #endif #ifdef?OPTION2 unix_version_of_option2(); #endif #elif? define(?OS_MSDOS?) #ifdef?OPTION2 msdos_version_of_option2(); #endif #endif
#ifndf?_HEADERNAME_H #define?_HEADERNAME_H #endif
符號 | 樣例值 | 含義 |
---|---|---|
屬性 | #define宏 | 函數(shù) |