iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 22
0
自我挑戰組

30 Days 如何把 C 語言偽裝成高階語言 OWO /系列 第 23

Day 22:重溫 可變參數函數、可變參數宏 __VA_ARGS__

▌第一次閱讀本系列的,可以先看:

本系列的大綱 傳送門


▌可變參數函數:

需要 #include <stdarg.h>
包括一個類型,四個巨集函數

類型: va_list ,用來儲存巨集va_arg()與巨集va_end()所需資訊
巨集函數: va_start(), va_arg(), va_end(), va_copy()

除了 va_copy() 是 C99 外,其餘都是相容於 C89 。


▌用法例子:

int sum(int num, ...){
    
    va_list args;
    va_start(args, num);
    
    int sum = 0;
    for(i = 0; i < num; i++){
        sum += va_arg(args, int);
    }
    
    va_end(args);
    
    return sum;
}

先創建一個 va_list 類型的變數,

va_start() 有兩個參數,第一個是剛剛宣告的變數( va_list 類型),
第二個是 可變參數 ... 前一個的變數名,這裏是 num

va_arg() 用於獲得額外參數的數值,同樣有兩個參數,
第一個也是剛剛宣告的變數,第二個是 載入的參數類型

注意 載入的參數類型 不可為

  • char、signed char、unsigned char
  • short、unsigned short
  • signed short、short int、signed short int、unsigned short int
  • float

會有默认参数提升(default argument promotions)

  • float类型的实际参数将提升到double
  • char、short和相应的signed、unsigned类型的实际参数提升到int
  • 如果int不能存储原值,则提升到unsigned int

可参看 C语言可变长参数函数与默认参数提升

va_end() ,像 fclose() 一樣把可變參數關掉。
一個參數,va_list 類型的變數。

詳細實現及原理可參看 可变参数函数详解 - clover_toeic - 博客园


▌可變參數宏 VA_ARGS

由 C99 引入,

聲明語法類似於可變參數函數:逗號後面三個句點"...",表示一個或多個參數。
但常見編譯器也允許傳遞0個參數。
宏擴展時使用特殊標識符__VA_ARGS__表示所傳遞的參數的替換。
沒辦法訪問可變參數列表內的單個參數,也不能獲知多少個參數被傳遞。

例子:

#define foo(f, ...) printf(f, __VA_ARGS__)

foo("%d%d", x, y); 等價 printf("%d%d", x, y);
接收了兩個額外參數。

注意 沒辦法訪問可變參數列表內的單個參數,也不能獲知多少個參數被傳遞。
所以不能夠像可變參數函數一樣,
可以以“簡單直觀”的方法去實現可變參數的 sum()。


▌額外的逗號:

若果額外參數的數目為 0 ,即 foo("123");
會被展開為 printf("123",) ,這裏出現了一個額外的逗號

可把 __VA_ARGS__ 改為 ##__VA_ARGS__
去提示編譯器,會自動把逗號去除。

Visual C++ 貌似不用提醒也會自動去除。


▌參考資料:

stdarg.h - 維基百科,自由的百科全書
https://zh.wikipedia.org/wiki/Stdarg.h
可变参数函数详解 - clover_toeic - 博客园
https://www.cnblogs.com/clover-toeic/p/3736748.html

可變參數宏 - 維基百科,自由的百科全書
https://zh.wikipedia.org/wiki/%E5%8F%AF%E5%8F%98%E5%8F%82%E6%95%B0%E5%AE%8F
C语言可变参数宏定义方法 - 做一个有技术追求的人 - CSDN博客
https://blog.csdn.net/skyflying2012/article/details/38436711
__VA_ARGS__ 與 ## 小檔案 變數是否存在 去除逗號 , @ CC :: 隨意窩 Xuite日誌
https://blog.xuite.net/csiewap/cc/66750644-VA_ARGS+%E8%88%87+%23%23+%E5%B0%8F%E6%AA%94%E6%A1%88+%E8%AE%8A%E6%95%B8%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8+%E5%8E%BB%E9%99%A4%E9%80%97%E8%99%9F+%2C
microsoft Variadic 巨集
https://msdn.microsoft.com/zh-tw/library/ms177415.aspx


上一篇
Day 21:重溫前置處理器、巨集( #, ## )、預先定義的巨集
下一篇
Day 23: goto、標記、爭議及反面例子
系列文
30 Days 如何把 C 語言偽裝成高階語言 OWO /31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言