C/C++可變參數機制

在寫一個函數時,經常會有實現一個參數未知或不是常數的函數的需求。printf就是這樣的一個函數,在 Section 9.11中有詳細描述。接下來的例子將想你展示如何聲明一個這樣的函數。

int f(int, ... ) {
        .
        .
        .
}


int g() {
        f(1,2,3);
}
//Example 9.5

爲了得到被調用的函數的參數, <stdarg.h>頭文件中函數的聲明必須要被包括。這就引入了一個新類型va_list和三個對這個類型的對象的函數,它們是va_start, va_arg, 和va_end

在獲取一個變量參數列表之前,va_start一定要被調用,它被定義成

#include <stdarg.h>
void va_start(va_list ap, parmN);

va_start 宏初始了ap爲 接下來的函數va_argva_end所用。va_start的第二個參數parmN是作爲標識符命名了函數定義(在…前面那個)中變量參數表中最右邊參數。標識符parmN不能被聲明成register的存儲類或作爲一個函數或數組類型。

一旦初始化了,提供的這些參數就可以在接下來被va_arg 宏所使用。這很奇怪,因爲返回的類型是被宏的一個參數所定義的。注意這不可能由一個真正的函數去實現,而只能是一個宏。它被定義成

#include <stdarg.h>
type va_arg(va_list ap, type);

每次對這個宏的調用都會提取參數列表中的下一個參數作爲一個特定類型的值。va_list 參數必須是一個被va_start初始化的參數。如果接下來的參數不是特定的那種類型,那麼這成了一個未定義的行爲。在這裏要注意避免可能由於數值類型轉換而導致的問題。用char或者short作爲va_arg的第二個參數總是錯誤的:這些類型總是會提升到signed intunsigned int中的一個,以及float 會轉換成double。注意是執行時才定義是否對象聲明爲類型char, unsigned char, unsigned short ,無符號的那些位閾會提升至unsigned int,還是複雜化va_arg。這可能是一些預期以外的微妙的事情發生的地方;時間會說明一切。

va_arg被調用卻沒有更多的參數時,這種行爲也是不被定義的。

這裏的type(類型)參數的類型名,必須可以簡單地用添加一個*來轉換成一個指向一個對象的指針 。簡單類型如char就可以(因爲char *就是一個指向字符對象的指針),但是字符數組就不行(char []不能用添加*的方式轉換成‘指向字符數組的指針’)。好在,數組還是很好處理的–只要記住數組名作爲函數調用實參的時候本身就會轉換成一個指針就可以了。對於一個’字符數組’參數類型而言,正確的type將會是char *

當所有參數都被處理了的時候,va_end函數應該被調用,這將會防止va_list裏的那些已經被用過的參數再次呈遞上去。如果va_end沒有被使用,這種行爲是未定義的。

在調用va_end以後,整個參數列表可以用再調用va_start 的方法被重新遍歷。va_end函數被聲明爲

#include <stdarg.h>
void va_end(va list ap);

接下來的例子展示了va_start,va_arg, 和va_end在實現一個返回最大整型參數的函數裏的用法

#include <stdarg.h>
#include <stdio.h>


int maxof(int, ...) ;
void f(void);


main(){
        f();
        exit(EXIT_SUCCESS);
}


int maxof(int n_args, ...){
        register int i;
        int max, a;
        va_list ap;


        va_start(ap, n_args);
        max = va_arg(ap, int);
        for(i = 2; i <= n_args; i++) {
                if((a = va_arg(ap, int)) > max)
                        max = a;
        }


        va_end(ap);
        return max;
}


void f(void) {
        int i = 5;
        int j[256];
        j[42] = 24;
        printf("%d\n",maxof(3, i, j[42], 0));
}
//Example 9.6

閱讀原文

發佈了31 篇原創文章 · 獲贊 12 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章