概述
由於在C語言中沒有函式重載,解決不定數目函式參數問題變得比較麻煩;即使採用C++,如果參數個數不能確定,也很難採用函式重載.對這種情況,有些人採用指針參數來解決問題.下面就c語言中處理不定參數數目的問題進行討論
在VC++6.0的include有一個stdarg.h頭檔案,有如下幾個宏定義:
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一個可選參數地址
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一個參數的值
#define va_end(ap) ( ap = (va_list)0 ) // 將指針置為無效
如果對以上幾個宏定義不理解,可以略過,接著看後面的內容.
在進程中,堆疊地址是從高到低分配的.當執行一個函式的時候,將參數列表入棧,壓入堆疊的高地址部分,然後入棧函式的返回地址,接著入棧函式的執行代碼,這個入棧過程,堆疊地址不斷遞減,一些黑客就是在堆疊中修改函式返回地址,執行自己的代碼來達到執行自己插入的代碼段的目的.
總之,函式在堆疊中的分布情況是:地址從高到低,依次是:函式參數列表,函式返回地址,函式執行代碼段.
堆疊中,各個函式的分布情況是倒序的.即最後一個參數在列表中地址最高部分,第一個參數在列表地址的最低部分.參數在堆疊中的分布情況如下:
最後一個參數
倒數第二個參數
...
第一個參數
函式返回地址
函式代碼段
代碼說明
void arg_test(int i, ...);
int main(int argc,char *argv[])
{
int int_size = _INTSIZEOF(int);
printf("int_size=%d\n", int_size);
arg_test(0, 4);
//arg_cnt(4,1,2,3,4);
return 0;
}
void arg_test(int i, ...)
{
int j=0;
va_list arg_ptr;
va_start(arg_ptr, i);
printf("&i = %p\n", &i);//列印參數i在堆疊中的地址
printf("arg_ptr = %p\n", arg_ptr);//列印va_start之後arg_ptr地址
/*這時arg_ptr應該比參數i的地址高sizeof(int)個位元組,即指向下一個參數的地址*/
j=*((int *)arg_ptr);
printf("%d %d\n", i, j);
j=va_arg(arg_ptr, int);
printf("arg_ptr = %p\n", arg_ptr);//列印va_arg後arg_ptr的地址
/*這時arg_ptr應該比參數i的地址高sizeof(int)個位元組,即指向下一個參數的地址,如果已經是最後一個參數,arg_ptr會為NULL*/
va_end(arg_ptr);
printf("%d %d\n", i, j);
}
說明:
int int_size = _INTSIZEOF(int);得到int類型所占位元組數
va_start(arg_ptr, i); 得到第一個可變參數地址
根據定義(va_list)&v得到起始參數的地址, 再加上_INTSIZEOF(v) ,就是其實參數下一個參數的地址,即第一個可變參數地址.
j=va_arg(arg_ptr, int); 得到第一個可變參數的值,並且arg_ptr指針上移一個_INTSIZEOF(int),即指向下一個可變參數的地址.
va_end(arg_ptr);置空arg_ptr,即arg_ptr=(void *)0;
擴展閱讀
相關領域:c語言 java BASIC Microsoft Visual C++ vc vhdl j2ee linux UML VF asp VB delphi JSP sql perl windows 彙編語言 C SHARP c語言程式設計 html。