CWKSC's blog | 博客

可變參數宏 __VA_ARGS__

Featured image

目錄: C/C++ Macro 宏系列 | CWKSC’s blog | 博客

__VA_ARGS__ 可變參數宏

宏參數列表以 ... 結尾,__VA_ARGS__ 會完整無缺地把輸入到 ... 的内容展開

#define foo(...) __VA_ARGS__

foo(x, y) // x, y
foo(42, meow, owo   MEOW!!!) // 42, meow, owo MEOW!!!

一如以往,參數會被轉換成 Token 序列,所以:

▌常見用法

#define debug_printf(str, ...) \
    printf("[%s] [%s] [line%d] : " str, \
        __FILE__, __func__, __LINE__, __VA_ARGS__)

void Foo(){
    debug_printf("test %d", 42);
    // 下面是展開步驟 :
    printf("[%s] [%s] [line%d] : " str, __FILE__, __func__, __LINE__, __VA_ARGS__);
    printf("[%s] [%s] [line%d] : " "test %d", __FILE__, __func__, __LINE__, 42);
    printf("[%s] [%s] [line%d] : " "test %d", "D:\\main.cpp", "Foo", 6, 42);
    printf("[%s] [%s] [line%d] : test %d", "D:\\main.cpp", "Foo", 6, 42);
}

輸出:
[D:\\main.cpp] [Foo] [line6] : test 42

三個步驟:

  1. 輸入參數替換 ( str, __VA_ARGS__
  2. 預定義宏展開 ( __FILE__, __func__, __LINE__
  3. 鄰近字串符合併 ( "ab" "cd" —> "abcd"

## __VA_ARGS__ 去除額外的逗號

這是編譯器擴展

想一想,如果額外參數的數量為

以上面那個作為例子,例如 debug_printf("42")

(只輸入了一個參數,... 並沒有接收任何東西)

展開時就會出現了一個額外的逗號,因此編譯會出錯

我們可以把 __VA_ARGS__ 改為 ## __ VA_ARGS__ ,編譯器會自動把前面的逗號去除

如果不想用編譯器擴展,可以看看:

c - Standard alternative to GCC’s ##__VA_ARGS__ trick? - Stack Overflow

下面有一個喪心病狂的答案 …… 我只是個人類(瑟瑟發抖.jpg

▌Visual Studio 不一致的行為

後記:Visual Studio 更新了

Visual Studio 在處理 __VA_ARGS__ 時出現了與其他編譯器不一致的行為

__VA_ARGS__ 會被視為一個整體的 Token 處理

這意味在未重掃描之前會被當成一個參數處理

#define get_args0(args0, ...) args0
#define foo(...) get_args0(__VA_ARGS__)

foo(x, y)
get_args0(__VA_ARGS__)
get_args0(x, y)  // x, y 被視為一個整體
x, y

foo(x, y) 展開了 x, y

我們預期的是展開為 x 而不是 x, y

重掃描可以解決這個問題,這個另一篇文章會講,就不在這裏說了

▌Visual Studio 這樣的行為有什麼意義?

如果有超多層的宏函數的時候,而你又不想 __VA_ARGS__中途被展開

這種特性可以讓您自行決定預期的 __VA_ARGS__ 在什麼時候才生效

但這麻煩到很多開發者,也坑死了超多人

不過在超多層宏的時候你反而會讚歎這個巧妙的設計

▌結語

__VA_ARGS__ 可變參數宏要用上手很簡單

不少有趣的宏函數都是圍繞著 __VA_ARGS__ 可變參數宏開發

衍生了很多千奇百怪的用法

其實結語也不知道說什麽好

所以就醬啦 OW< 拜~

CWKSC

Author 作者

CWKSC

喜歡編程,會一點點鋼琴,會一點點畫畫,喜歡使用顏文字 About me 關於我

For any comments or discussions on my blog post, you can open an issue here

對於我博客文章的任何評論或討論,可以在這裏開一個 issue

Feel free to give your comments. OW<