可變參數、不定參數(va_list、va_start、va_arg、va_end)

可變參數、不定參數是什麼

我這裏所說的可變參數或不定參數是指, 方法中的某個形式參數可以接收多個參數(不確定個數的參數)。就比如, 下面的一些系統的方法:

[NSArray arrayWithObjects:@"first", @"second", @"third"];
[[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:nil cancelButtonTitle:@ otherButtonTitles:@"first", @"second", @"third", nil];

// Method Reference

+ (instancetype)arrayWithObjects:(ObjectType)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
- (instancetype)initWithTitle:(nullable NSString *)title message:(nullable NSString *)message delegate:(nullable id /*<UIAlertViewDelegate>*/)delegate cancelButtonTitle:(nullable NSString *)cancelButtonTitle otherButtonTitles:(nullable NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION

以上這兩個方法都是系統的方法, NSArray方法中的firstObjUIAlertView方法中的otherButtonTitles都是可變參數。

實現可變參數的方法

自定義一個方法printMessages: 實現可變參數:

- (void)printMessages:(nullable NSString *)messages, ... NS_REQUIRES_NIL_TERMINATION {
    if (messages) {
        // 取出第一個參數(這是固定參數)
        NSLog(@"固定參數: %@", messages);
        // 定義一個參數列表指針
        va_list args;
        // 存放所取參數的指針
        NSString *arg;
        // 初始化va_list變量
        va_start(args, messages);
        // 取出va_list中存儲的可變參數(不包含固定參數), 取出後args指向參數列表中的下一個參數
        while ((arg = va_arg(args, NSString *))) {
            NSLog(@"可變參數: %@", arg);
        }
        // 清空參數列表,並將va_list的指針置爲NULL
        va_end(args);
    }
}

調用方法:

   [self printMessages:@"first", @"second", @"third", nil];

打印結果:

固定參數: first
可變參數: second
可變參數: third

實現可變參數的原理

在上面的代碼中, 讀取可變參數的過程其實就是在堆棧中,使用指針, 遍歷堆棧段中的參數列表, 從低地址到高地址一個一個地把參數內容讀出來的過程。

歸根到底還是通過 va_listva_startva_argva_end 這四個宏的功能來實現的。它們就是C語言中用來解決變參問題的一組宏。

它們的具體作用如下:
va_list: 用於獲取不確定個數的參數, 保存宏 va_startva_argva_end 所需信息的一種類型。爲了訪問可變參數列表中的參數,必須聲明一個 va_list類型的指針。
va_start: 初始化 va_list,獲取可變參數列表的第一個參數的地址。初始化結果供宏va_argva_end使用。
va_arg: 獲取可變參數的當前參數,返回指定類型並將指針指向下一參數
va_end: 清空va_list可變參數列表,並該指針置爲NULL

Demo下載地址:
Demo
拓展資料:
va_listva_startva_argva_end

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章