getchar、putchar 常被實現為宏對比三種絕對值宏:
#define ABS(x) x>0?x:-x // 危險:無括號保護
#define ABS1(x) (x)>0?(x):-(x) // 部分保護
#define ABS2(x) ((x)>0?(x):-(x)) // 完整保護(推薦)
測試代碼:
int a=1, b=4;
printf("%d\n", ABS(a-b)); // -5 錯誤:展開為 1-4>0?1-4:-1-4
printf("%d\n", ABS1(a-b)); // 3 正確
int c=4, d=1;
printf("%d\n", ABS1(c-d)-1); // 3 錯誤:展開為 (4-1)>0?(4-1):-(4-1)-1
printf("%d\n", ABS2(c-d)-1); // 2 正確
鐵律:宏參數在定義中每次出現都要加括號,整個表達式也要加外層括號。
#define PSQR(x) printf("The square of "#x" is %d\n", (x)*(x))
PSQR(y); // The square of y is 25
PSQR(2+4); // The square of 2+4 is 36
#x 將參數轉為字符串字面量,便於調試輸出。
#define PR(X, ...) printf("Message " #X ": " __VA_ARGS__)
PR(1, "X=%g\n", x);
PR(2, "X=%.2f, y=%.4f\n", x, y);
// 編譯需鏈接數學庫:gcc variadic.c -lm
注意:... 只能替代最後的參數,C99 標準引入。
| 宏 | 含義 | 示例輸出 |
|---|---|---|
| __FILE__ | 當前源文件名 | predef.c |
| __DATE__ | 編譯日期 | Dec 13 2013 |
| __TIME__ | 編譯時間 | 22:52:07 |
| __LINE__ | 當前行號 | 10 |
| __func__ | 當前函數名(C99) | main |
| __STDC_VERSION__ | C 標準版本號 | 199901L (C99) |
這些宏在日誌輸出、調試斷言、版本資訊嵌入等場景極其有用。
切記:預處理器只做文本替換,不懂 C 語法,不做類型檢查,不計算常量表達式(除 #if 條件編譯外)。濫用宏易導致難以調試的錯誤,能用 const/inline/enum 替代時優先考慮。