1. 程式人生 > >gcc巨集定義可變引數列表(__VA_ARGS__)

gcc巨集定義可變引數列表(__VA_ARGS__)

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用##解決該問題: 如果可變引數列表為空,就會將緊挨著")"的“,”去掉。