1. 基本形式
#define name replacement_text
通常情況下,#define
指令占一行,替換文本是 define
指令行尾部的所有剩余部分,但也可以把一個較長的宏定義分成若干行,這時需要在待續的行末尾加上一個反斜杠符 ``。
宏定義也可以帶參數,這樣可以對不同的宏調用使用不同的替換文本。例:
#define max(A, B) ((A) > (B) ? (A) : (B))
2. 宏展開中的陷阱
仔細考慮一下 max
的展開式,其中的表達式會被計算兩次,因此如果表達式中包含自增運算符或輸入/輸出等行為,則會出現不正確的情況,例如上述的宏 max
:
max(i++, j++) // wrong
另外還需要注意,適當使用圓括號以保證計算次序的正確性,例如:
#define square(x) x * x // wrong
當用 square(z+1)
調用該宏定義時會出錯。
3. #undef
在頭文件 <stdio.h>
中,getchar
與 putchar
函數在實際中常常被定義為宏,這樣可以避免處理字符時調用函數所需的運行時開銷。<ctype.h>
頭文件中定義的函數也常常是通過宏實現的。
可以通過 #define
取消名字的宏定義,這樣做可以保證后續的調用是函數調用,而不是宏調用:
#undef getchar
int getchar(void) { ... }
4. 宏參數、#
和 ##
如果在宏定義的替換文本中,參數名以 #
作為前綴則結果將被擴展為由實際參數替換該參數的帶引號的字符串。例如,可以將它與字符串連接運算結合起來編寫一個調試打印宏:
#define dprint(expr) printf(#expr " = %gn", expr)
使用語句
dprint(x/y);
調用該宏時,該宏將被擴展為:
printf("x/y" " = %gn", x/y);
其中的字符串被拼接起來了,這樣,該宏調用的效果等價於
printf("x/y = %gn", x/y);
預處理器運算符 ##
為宏擴展提供了一種連接實際參數的手段。如果替換文本中的參數與 ##
相鄰,則該參數將被實際參數替代,##
與前后的空白符將被刪除,並對替換后的結果重新掃描。例如,下面定義的宏 paste
用於連接兩個參數:
#define paste(front, back) front ## back
因此,宏調用 paste(name, 1)
的結果將建立記號 name1
。
參考文獻:
- Brian W. Kernighan, Dennis M. Ritchie.The C Programming Language (Second Edition)[M].機械工業出版社:北京,2004:76-77.