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

字號(hào):

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