巨集替換

最簡單的巨集替換形式是定義一個 manifest constant,如

#define ARRSIZE 100
int array[ARRSIZE];

這定義了一個類似函式的巨集,它將變數乘以 10 並儲存新值:

#define TIMES10(A) ((A) *= 10)

double b = 34;
int c = 23;

TIMES10(b);   // good: ((b) *= 10);
TIMES10(c);   // good: ((c) *= 10);
TIMES10(5);   // bad:  ((5) *= 10);

替換是在對程式文字的任何其他解釋之前完成的。在第一次呼叫 TIMES10 時,定義中的 A 名稱被替換為 b,然後將這樣擴充套件的文字放在呼叫的位置。請注意,TIMES10 的這個定義並不等同於

#define TIMES10(A) ((A) = (A) * 10)

因為這可以評估替換 A 兩次,這可能會產生不必要的副作用。

下面定義了一個類似函式的巨集,其值是其引數的最大值。它具有為任何相容型別的引數工作以及生成內聯程式碼而不需要函式呼叫的開銷的優點。它的缺點是第二次評估其中一個或另一個引數(包括副作用),並且如果多次呼叫則生成比函式更多的程式碼。

#define max(a, b) ((a) > (b) ? (a) : (b))

int maxVal = max(11, 43);              /* 43 */
int maxValExpr = max(11 + 36, 51 - 7); /* 47 */

/* Should not be done, due to expression being evaluated twice */
int j = 0, i = 0;
int sideEffect = max(++i, ++j);       /* i == 4 */

因此,在生產程式碼中通常會避免多次評估其引數的巨集。從 C11 開始,_Generic 功能允許避免這種多次呼叫。

巨集擴充套件中的豐富括號(定義的右側)確保引數和結果表示式被正確繫結並且很好地適合呼叫巨集的上下文。