C 變長引數函式小結

2021-07-14 22:05:57 字數 2186 閱讀 4277

變長引數的函式,即引數個數可變、引數型別不定的函式。設計乙個引數個數可變、引數型別不定的函式是可能的,最常見的例子是printf函式、scanf函式和高階語言的format函式。在c/c++中,為了通知編譯器函式的引數個數和型別可變(即是不定的、未知的),就必須以三個點結束該函式的宣告。例如:

//printf函式的宣告

int printf(const char * _format, ...);

//scanf函式宣告

int scanf(const char * _format, ...);

//自定義變長引數函式func的宣告

int func(int a, int b, ...);

上面func函式的宣告指出該函式至少有兩個整型引數和緊隨其後的0個或多個型別未知的引數。在c/c++中,任何使用變長引數宣告的函式都必須至少有乙個指定的引數(又稱強制引數),即至少有乙個引數的型別是已知的,而不能用三個點省略所有引數的指定,且已知的指定引數必須宣告在函式最左端。

變長引數函式的實現

含有變長引數的函式是怎麼實現的呢?變長引數函式的實現其實關鍵在於怎麼使用引數,指定了的引數好說,直接使用指定的引數名稱訪問,但未指定的引數呢?我們知道函式呼叫過程中引數傳遞是通過棧來實現的,一般呼叫都是從右至左的順序壓引數入棧,因此引數與引數之間是相鄰的,知道前乙個引數的型別及位址,根據後乙個引數的型別就可以獲取後乙個引數的內容。對於變長引數函式,結合一定的條件,我們可以根據最後乙個指定引數獲取之後的省略引數內容。如,對於函式func,我們知道了引數b的位址及型別,就可知道第乙個可變引數的棧位址(如果有的話),如果知道第乙個可變引數的型別,就可知道第乙個可變引數的內容和第二個可變引數的位址(如果有的話)。以此類推,可以實現對可變引數函式的所有引數的訪問。

那麼,要怎麼指定上訴的「一定的條件」呢?最簡單的方法就像printf等函式一樣,使用格式化佔位符。分析格式化字串引數,通過事先定義好的格式化佔位符可知可變引數的型別及個數,從而獲取各個引數內容。一般對於可變引數型別相同的函式也可直接在強制引數中指定可變引數的個數和型別,這樣也能獲取各個引數的內容。

無論哪種,都涉及對棧位址偏移的操作。結合棧儲存模式和系統資料型別的字長,我們可根據可變引數的型別很容易得到棧位址的偏移量。

變長引數函式的簡單運用:

// va_arg_test.cpp : 定義控制台應用程式的入口點。

////訪問可變引數流程

//va_list args; //定義乙個可變引數列表

//va_start(args,arg); //初始化args指向強制引數arg的下乙個引數

//va_arg(args,type); //獲取當前引數內容並將args指向下乙個引數

//... //迴圈獲取所有可變引數內容

//va_end(args); //釋放args

#include "stdafx.h"

#include #include #include /// @brief 利用變長引數函式進行求和運算

/// @param[in] n : 指定後面有多少可變引數

/// @remark 第乙個引數為強制引數

/// @return 得到求和結果

double sum(unsigned int n, ...)

va_end(args);//釋放args

return sum;

}/// @brief 利用變長引數函式格式化字串

/// @param[in] format : 類似printf中第乙個引數

/// @remark

/// @return 格式化後的字串

std::string format(const char* format, ...)

va_end(ap);

return var_str;}//

int _tmain(int argc, _tchar* argv)

對於可變引數函式的呼叫有一點需要注意:

實際的可變引數的個數必須比前面強制引數中指定的個數要多,或者不小於。也即後續引數多一點不要緊,但不能少!如果少了則會訪問到函式引數以外的堆疊區域,這可能會把程式搞崩掉。前面強制引數中指定的型別和後面實際引數的型別不匹配也有可能造成程式崩潰。 

c 變長引數

c 在支援變長引數時,用到了三個巨集,va start va arg va end,和乙個資料型別va list。談談我對他們使用上理解吧 va list ptr 首先定義乙個該型別的指標 va start ptr,parm1 該型別指標和入參的第乙個引數關聯 type va arg ptr,tpy...

C 變長引數

如果c 的變長引數經過了多輪的呼叫,就可能失去作用 間接引址,但是只能引用到第乙個變長引數。va start marker,format s loggers filename loglinef format,va arg marker,va list va end marker va start m...

C 系列 函式可變長引數

一 基礎部分 1.1 什麼是可變長引數 可變長引數 顧名思義,就是函式的引數長度 數量 是可變的。比如 c 語言的 printf 系列的 格式化輸入輸出等 函式,都是引數可變的。下面是 printf 函式的宣告 int printf const char format,可變引數函式宣告方式都是類似的...