gcc巨集定義可變引數列表(__VA_ARGS__)
阿新 • • 發佈:2019-02-10
gcc編譯器巨集定義做了許多擴充套件,支援巨集定義可變引數列表。
1. 在不支援可變引數列表之前,為了寫支援不同引數的列印巨集定義,列印Log的巨集定義可能會這樣寫:
這種寫法弊端很明顯,只要引數個數不一樣,就得多寫一個巨集定義。#define Log1(format, args1) printf(format, args1) #define Log2(format, args1, args2) printf(format, args1, args2) #define Log3(format, args1, args2, args3) printf(format, args1, args2, args3) Log1("%s\n", "a"); Log2("%s %s\n", "a", "b"); Log3("%s %s %s\n", "a", "b", "c");
2. 在不支援可變引數列表之前,在很多原始碼裡面經常看到如下寫法:
#define Log(args) printf args
Log(("%s %s\n", "a", "b"));
這樣做相當於對printf做了簡單的替換,只是語義上更好理解一點而已。
3. C99之前gcc對巨集定義可變引數列表的支援。
現在我們可以用類似函式可變引數列表的方式作用於巨集定義#define Log(format, args...) printf(format, ##args) Log("%s\n", "abc"); Log("%s %d\n", "abc", 10); Log("%s %d %d\n", "abc", 10, 10);
4. C99以後gcc對巨集定義可變引數列表的支援。
#define Log(format, ...) printf(format, ##__VA_ARGS__)
Log("%s\n", "abc");
Log("%s %d\n", "abc", 10);
Log("%s %d %d\n", "abc", 10, 10);
C99以後,gcc在在預處理階段,專門用可變引數替換__VA_ARGS__巨集定義,__VA_ARGS__為gcc自定義的巨集定義。
5. 細心地同學可能會注意到在可變引數列表中使用了##,為什麼要用##呢?
這是因為巨集定義只是在預處理階段簡單地替換, 如果可變引數列表為空,巨集定義將會多出一個","
#define Log(format, ...) printf(format, __VA_ARGS__)
Log("abc"); // 替換後為 printf("abc", );
這種寫法會造成編譯錯誤,gcc用##解決該問題: 如果可變引數列表為空,就會將緊挨著")"的“,”去掉。