函數(shù)的可變參數(shù)詳談

字號:

可變參數(shù)的英文表示為:variable argument.
    它在函數(shù)的定義時,用三個點號'.'表示,用逗號與其它參數(shù)分隔.
    可變參數(shù)的特點:不像固定參數(shù)那樣一一對應(yīng),也不像固定參數(shù)有固定的參數(shù)類型和參數(shù)名稱;可變參數(shù)中個數(shù)不
    定可是傳入的是一個參數(shù)也可以是多個;可變參數(shù)中的每個參數(shù)的類型可以不同,也可以相同;可變參數(shù)的每個參數(shù)并沒有
    實際的名稱與之相對應(yīng).
    由此可見,可變參數(shù)的形式非常自由而富有彈生.因些,它給那些天才程序員有更大地想象和發(fā)揮空間.
    然而,更多地自由,同樣也加大操作上的難度.
    以下就對可變參數(shù)的幾個方面作一定的介紹.
    1)可變參數(shù)的存儲形式.
    大家都知道,一般函數(shù)的形參屬于局部變量.而局部變量就是存儲在內(nèi)存的棧區(qū)(所謂的棧區(qū):由編譯器自動分配釋放,
    存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。).可變參數(shù)也是存儲在內(nèi)存棧區(qū).
    在對函數(shù)的形參存儲的時侯,編譯器是從函數(shù)的形參的右邊到左邊逐一地壓棧,
    這樣保證了棧頂是函數(shù)的形參的第一個參數(shù)(從左到右數(shù)).而80x86平臺下的內(nèi)存分配順序是從高地址內(nèi)存到低地址內(nèi)存.
    因此,函數(shù)的形參在內(nèi)存的存儲形式如下圖(以fun(int var1,int var2,...,int var3,int var4)為例):
    棧區(qū):
    |棧頂 低地址
    |第一個固定參數(shù)var1
    |可變參數(shù)前的第一個固定參數(shù)var2
    |可變參數(shù)的第一個參數(shù)
    |...
    |可變參數(shù)的最后一個參數(shù)
    |函數(shù)的倒數(shù)第二個固定參數(shù)var3
    |函數(shù)的最后一個固定參數(shù)var4
    |...
    |函數(shù)的返回地址
    |...
    |棧底 高地址
    2)使用可變參數(shù)所用到頭文件和相關(guān)宏說明
    在此,以TC2.0編譯器為參考對象來說明.
    可變參數(shù)的相關(guān)定義在TC2.0的名為"STDARG.H"的頭文件中.
    此文件為:
    /* stdarg.h
    Definitions for ACCESSing parameters in functions that accept
    a variable number of arguments.
    Copyright (c) Borland International 1987,1988
    All Rights Reserved.
    */
    #if __STDC__
    #define _Cdecl
    #else
    #define _Cdecl cdecl
    #endif
    #if !defined(__STDARG)
    #define __STDARG
    typedef void *va_list;
    #define va_start(ap, parmN) (ap = ...)
    #define va_arg(ap, type) (*((type *)(ap))++)
    #define va_end(ap)
    #define _va_ptr (...)
    #endif
    以上為"STDARG.H"的內(nèi)容.
    該文件定義了使用可變參數(shù)所用到的數(shù)據(jù)類型:typedef void *va_list;
    va_start(ap,parmN)起到初始化,使用得ap指向可變參數(shù)的第一個參數(shù).ap的類型為va_list,
    parmN為可變參數(shù)的前面一個固定參數(shù).
    va_arg(ap,type)獲得當前ap所指向的參數(shù),并使ap指向可變參數(shù)的下一個參數(shù),type為需要獲得的參數(shù)的類型.
    va_end(ap) 結(jié)束可變參數(shù)獲取.
    3)可變參數(shù)的使用實例
    實例目的:用可變參數(shù)來實現(xiàn)個數(shù)不定的字符串的傳遞,并顯示傳遞過來的字符串.
    #include
    #include
    #include
    void tVarArg(int num,...);/*num為可變參數(shù)的個數(shù)*/
    int main(void)
    {
    clrscr();
    tVarArg(5,"Hello! ","My ","name ","is ","neverTheSame.\n");
    tVarArg(8,"This ","is ","an ","example ","about ","variable-argument ","in ","funtion");
    getch();
    return 0;
    }
    void tVarArg(int num,...)
    {
    va_list argp; /*定義一個指向可變參數(shù)的變量*/
    va_start(argp,num); /*初始化,使用argp指向可變參數(shù)的第一個參數(shù)*/
    while(--num>=0)
     printf("%s",(va_arg(argp,char*)));/*va_arg(argp,char*)獲得argp所指向的參數(shù),
     并使用argp指向下一個參數(shù),char*使用所獲得的參數(shù)的類型轉(zhuǎn)換為char*型.*/
    va_end(argp); /*結(jié)束可變參數(shù)獲取*/
    return ;
    }
    4)可變參數(shù)的使用需要注意的問題
    1.每個函數(shù)的可變參數(shù)至多有一個.
    2.va_start(ap,parmN)中parmN為可變參數(shù)前的一個固定參數(shù).
    3.可變參數(shù)的個數(shù)不確定,完全由程序約定.
    4.可變參數(shù)的類型不確定,完全由va_arg(ap,type)中的type指定,然后就把參數(shù)的類型強制轉(zhuǎn)換.
    而printf()中不是實現(xiàn)了識別參數(shù)嗎?那是因為函數(shù)
    printf()是從固定參數(shù)format字符串來分析出參數(shù)的類型,再調(diào)用va_arg
    的來獲取可變參數(shù)的.也就是說,你想實現(xiàn)智能識別可變參數(shù)的話是要通
    過在自己的程序里作判斷來實現(xiàn)的.
    5.編譯器對可變參數(shù)的函數(shù)的原型檢查不夠嚴格,對編程人員要求很高.