巨集定義有兩種:簡單巨集定義,帶引數的巨集定義。
簡單巨集定義:#define 識別符號 替換列表
#define
為常量命名的優點:
1. 程式會更易讀;
2. 程式更易於修改;
3. 可以幫助避免前後不一致或鍵盤輸入錯誤;
其他應用:
1. 可以對c語法做小的修改:
#define begin
// 之間的空格符是可以任意的
甚至可以定義:#define loop for( ;; )
2.對型別重新命名:#define bool int
但是,通常使用typedef 對型別重新命名
3.控制條件編譯:
帶引數的巨集定義#define 識別符號(x1,x2,x3,...,xn) 替換列表
如:
#define max(x,y) ((x)>(y) ? (x) :(y))
//替換列表中的引數都使用()括起來,可避免之間優先順序不同而出錯
可以包含空的引數列表:#define getchar() getc(stdin)
優點:
程式可能會稍微快些。乙個函式呼叫在執行時通常有些額外開銷—–儲存上下文資訊,複製引數的值等。而巨集的呼叫沒有。
巨集會更」通用」。與函式的引數不同,巨集的引數型別沒有型別。因此,只要預處理後的程式合法,巨集可以接收任何型別的引數。
缺點:
編譯後**通常會增加。
巨集引數沒有型別檢查。預處理器不會檢查巨集引數型別,也不會進行型別轉換
無法用乙個指標來指向乙個巨集。巨集在預處理的過程中被刪除,所以不存在類似的「指向巨集的指標」。
巨集可能會不止一次地計算它的引數。如果引數有附加作用,多次計算引數的值可能會產生意外的結果。例如:
n = max(i++,j);
即n = ((i++)>(j)?(i++):(j));
如果i>j, 那麼i可能會被計算兩次,結果n被賦錯誤值。
因此,為避免這種情況,最好不使用帶有附加作用的引數。
將乙個巨集的引數轉換為字串字量。它僅允許出現在帶引數的巨集的替換列表中。
例如:
#define print_int(x) printf(#x " = %d\n", x)
x之前的#通知預處理器根據 print_int 的引數建立乙個字串字面量。因此,呼叫print_int(i/j);
會變成printf("i/j"" = %d\n",i/j);
等價於printf("i/j = %d\n",i/j);
##運算子
可以將兩個記號連在一起,成為乙個記號。例如,#define mk_id(n) i##n
int mk_id(1),mk_id(2),mk_id(3);
等價於int i1,i2,i3;
##
用於同一功能,不同資料型別的函式的巨集定義,如:
#define generic_max(type) \
type
type##_max(
type
x, type
y) \
則generic_max(float)
等價於float float_max(float x,float y)
在建立較長的巨集時, 逗號號運算子很有用。可以用逗號運算子使替換列表包含一系列表示式,如:
#define echo(s) (gets(s), puts(s))
而,如果想在巨集的替換列表中包含一系列語句,可以用dowhile(0)
,如:
#define echo(s) \
do while(0)
注意:在使用echo巨集時,一定要加分號:echo(str);
名字描述
_line_
被編譯檔案行數
_file_
被編譯檔案名字
_date_
編譯的日期(m d y)
_time_
編譯時間(h:m:s)
_stdc_
如果編譯器接受標準c,那麼值為1
printf("linux (c) 2017 king software,inc.\n");
printf("complied on %s at %s\n, _date_, _time_");
程式開始執行,都會列印編譯的日期和時間,可以用來區分同一程式的不同版本。
_line_
和_file_
可以用來找錯誤。當乙個c程式因為被0除(或被0餘)而導致終止時,通常沒有資訊指明哪條除法(或余)導致錯誤。下面的巨集可以幫助查明錯誤的根源:
#define check_zero(divisor) \
if(divisor == 0) \
printf("**
*attempt to divide by zero on line %d of file %s
***\n", _line_, _file_);
check_zero巨集應該在(餘)除法運算前被呼叫:
check_zero(j);
k = i/j;
如果j = 0,顯示錯誤位置。
c語言庫提供了乙個通用的、用於錯誤檢測的巨集——assert巨集。
#if & #endif
#define debug 1
#if debug
....
#endif
如果debug設為1,預處理器就將#if 與 #endif 之間的語句保留到程式中,進行編譯;如果debug設為0,預處理器就刪去此段**。
對於沒有定義過的標識,#if 將它視為0。
defined運算子
使用:defined 識別符號
如果識別符號已經定義為巨集返回1,否則返回0。
#define debug //不需要給定值
#if defined debug
....
#endif
#ifdef & #ifndef
#ifdef //相當於#if defined
#ifndef //相當於#if !defined
#elif & #else
#if 識別符號
#if 表示式1
#elif 條件1
#elif 條件2
....
#else
#endif
elif
可以多次使用,else
只能在其中使用一次。
使用條件編譯的好處:
編寫多台機器或者多個作業系統的可移植程式。
#if defined windows
....
#elif defined unix
....
#elif defined os
....
#endif
編寫可以使用不同編譯器編譯的程式。
#if _stdc_ //標準c函式原型
....
#else //經典c函式宣告
....
#endif
為巨集提供預設定義。
#ifndef buffer_size
#define buffer_size 256
#endif
臨時遮蔽包含注釋的**。由於在標準c中不能用注釋巢狀
#if 0
包含注釋的**行
#endif
學習筆記 巨集定義基礎
在c c 中,巨集定義是由define完成的。define f a,b a b define g a a define h a g a f 1,2 輸出 12 輸出格式為 d 若為 s則報錯 g f 1,2 輸出 f 1,2 輸出格式 s h f 1,2 輸出 12 輸出格式 s 最外層巨集可替換至...
abs int 巨集定義 巨集定義和巨集方法
巨集定義和巨集方法 定義機型 define is iphone5 uiscreen instancesrespondtoselector selector currentmode cgsizeequaltosize cgsizemake 640,1136 uiscreen mainscreen cu...
預處理與巨集定義 筆記
2017 09 18 10 45 21 預處理1.預處理的指令和功能 以 開頭的語句 include 檔案包含 include 在標準庫下面找 include stdio.h 在當前工作路徑下查詢 自定義標頭檔案的包含形式 區別 查詢的路徑不相同 define 巨集定義 不帶引數的巨集和帶引數的巨集...