關(guān)于C/C++中可變參數(shù)的詳細介紹(va_list,va_start,va_arg,va_end)
由于在C語言中沒有函數(shù)重載,解決不定數(shù)目函數(shù)參數(shù)問題變得比較麻煩,即使采用C++,如果參數(shù)個數(shù)不能確定,也很難采用函數(shù)重載。對這種情況,提出了指針參數(shù)來解決問題。
如printf()函數(shù),其原型為:
int printf( const char* format, ...);
它除了有一個參數(shù)format固定以外,后面跟的參數(shù)的個數(shù)和類型是可變的,例如我們可以有以下不同的調(diào)用方法:
printf( "%d ",i);
printf( "%s ",s);
printf( "the number is %d ,string is:%s ", i, s);
如何實現(xiàn)其功能?
我們需要以下幾個宏定義:
(1)va_list
定義了一個指針arg_ptr, 用于指示可選的參數(shù).
(2)va_start(arg_ptr, argN)
使參數(shù)列表指針arg_ptr指向函數(shù)參數(shù)列表中的第一個可選參數(shù),argN是位于第一個可選參數(shù)之前的固定參數(shù), 或者說最后一個固定參數(shù).如有一va函數(shù)的聲明是void va_test(char a, char b, char c, ...), 則它的固定參數(shù)依次是a,b,c, 最后一個固定參數(shù)argN為c, 因此就是va_start(arg_ptr, c).
(3)va_arg(arg_ptr, type)
返回參數(shù)列表中指針arg_ptr所指的參數(shù), 返回類型為type. 并使指針arg_ptr指向參數(shù)列表中下一個參數(shù).返回的是可選參數(shù), 不包括固定參數(shù).
(4)va_end(arg_ptr)
清空參數(shù)列表, 并置參數(shù)指針arg_ptr無效.
(注:va在這里是variable-argument(可變參數(shù))的意思. 這些宏定義在stdarg.h中,所以用到可變參數(shù)的程序應(yīng)該包含這個頭文件)
也需你現(xiàn)在還是不能理解,別著急,現(xiàn)在從一個實例著手.定義這么一個函數(shù),函數(shù)的第一個參數(shù)是固定的,其余參數(shù)是可變的。定義為:
void simple_va_fun(int i,...); 其代碼為:
#include <iostream>
#include <stdarg.h>
using namespace std;
void simple_va_fun(int i,...);
int main(int argc,char *argv[])
{
simple_va_fun(100);
simple_va_fun(100,200);
simple_va_fun(100,200,'a');
return 0;
}
void simple_va_fun(int i,...)
{
va_list arg_ptr; //定義可變參數(shù)指針
va_start(arg_ptr,i); // i為最后一個固定參數(shù)
int j=va_arg(arg_ptr,int); //返回第一個可變參數(shù),類型為int
char c=va_arg(arg_ptr,char); //返回第二個可變參數(shù),類型為char
va_end(arg_ptr); // 清空參數(shù)指針
printf( "%d %d %c\n",i,j,c);
return;
}
代碼運行解釋:
(1)首先在函數(shù)里定義一個va_list型的變量,這里是arg_ptr,這個變量是指向參數(shù)的指針.
(2)然后用va_start宏初始化變量arg_ptr,這個宏的第二個參數(shù)是第一個可變參數(shù)的前一個參數(shù),是一個固定的參數(shù).
(3)然后用va_arg返回第一個可變的參數(shù),并賦值給整數(shù)j。va_arg的第二個參數(shù)是你要返回的參數(shù)的類型,這里是int型. 返回第一個可變參數(shù)后arg_ptr指向第二個可變參數(shù),用同樣的方法返回并賦值給c,類型為char類型。
(4)最后用va_end宏結(jié)束可變參數(shù)的獲取。
小結(jié):
可變參數(shù)的函數(shù)原理其實很簡單,而va系列是以宏定義來定義的,實現(xiàn)跟堆棧相關(guān).我們寫一個可變函數(shù)的C函數(shù)時,有利也有弊,所以在不必要的場合,我們無需用到可變參數(shù).如果在C++里,我們應(yīng)該利用C++的多態(tài)性來實現(xiàn)可變參數(shù)的功能,盡量避免用C語言的方式來實現(xiàn)。
附加:
參數(shù)在堆棧中分布:
在進程中,堆棧地址是從高到低分配的.當(dāng)執(zhí)行一個函數(shù)的時候,將參數(shù)列表入棧,壓入堆棧的高地址部分,然后入棧函數(shù)的返回地址,接著入棧函數(shù)的執(zhí)行代碼,這個入棧過程,堆棧地址不斷遞減,一些黑客就是在堆棧中修改函數(shù)返回地址,執(zhí)行自己的代碼來達到執(zhí)行自己插入的代碼段的目的. 總之,函數(shù)在堆棧中的分布情況是:地址從高到低,依次是:函數(shù)參數(shù)列表,函數(shù)返回地址,函數(shù)執(zhí)行代碼段. 堆棧中,各個函數(shù)的分布情況是倒序的.即最后一個參數(shù)在列表中地址最高部分,第一個參數(shù)在列表地址的最低部分.參數(shù)在堆棧中的分布情況如下:
最后一個參數(shù)
倒數(shù)第二個參數(shù)
...
第一個參數(shù)
函數(shù)返回地址
函數(shù)代碼段
相關(guān)文章
C++標準之(ravalue reference) 右值引用介紹
臨時對象的產(chǎn)生和拷貝所帶來的效率折損,一直是C++所為人詬病的問題,下面簡單地介紹一下Copy Elision、RVO,對此不感興趣的可以直接跳過2012-11-11C語言中操作進程信號的相關(guān)函數(shù)使用詳解
這篇文章主要介紹了C語言中操作進程信號的相關(guān)函數(shù)使用詳解,分別是signal()函數(shù)和kill()函數(shù)的用法,需要的朋友可以參考下2015-09-09Linux下動靜態(tài)庫的打包與使用指南(C/C++)
c++是面向?qū)ο蟮木幊陶Z言,比較方便實現(xiàn)某些第三方庫,比如翻譯其他面向?qū)ο笳Z言的代碼,比c語言要方便的多,下面這篇文章主要給大家介紹了關(guān)于Linux下C/C++動靜態(tài)庫的打包與使用的相關(guān)資料,需要的朋友可以參考下2023-02-02C語言實現(xiàn)linux網(wǎng)卡連接檢測的方法
這篇文章主要為大家詳細介紹了C語言實現(xiàn)linux網(wǎng)卡連接檢測的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06OpenCV中C++函數(shù)imread讀取圖片的問題及解決方法
利用C++函數(shù)imread讀取圖片的時候返回的結(jié)果總是空,而利用C函數(shù)cvLoadImage時卻能讀取到圖像。怎么回事?今天小編通過本教程給大家簡單說明原因2017-03-03matlab遺傳算法求解車間調(diào)度問題分析及實現(xiàn)源碼
這篇文章主要為大家介紹了matlab遺傳算法求解車間調(diào)度問題解析,文中附含詳細實現(xiàn)源碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-02-02