va_start和va_end使用詳解

本文主要介紹va_start和va_end的使用及原理。html

  在之前的一篇帖子Format MessageBox 詳解中曾使用到va_start和va_end這兩個宏,但對它們也只是泛泛的瞭解。ios

  介紹這兩個宏以前先看一下C中傳遞函數的參數時的用法和原理: 數據結構

1.在C中,當咱們沒法列出傳遞函數的全部實參的類型和數目時,能夠用省略號指定參數表函數

void foo(...);
void foo(parm_list,...);
這種方式和咱們之前認識的不大同樣,但咱們要記住這是C中一種傳參的形式,在後面咱們就會用到它。

 

2.函數參數的傳遞原理指針

  函數參數是以數據結構:棧的形式存取,從右至左入棧。orm

  首先是參數的內存存放格式:參數存放在內存的堆棧段中,在執行函數的時候,從最後一個開始入棧。所以棧底高地址,棧頂低地址,舉個例子以下:
void func(int x, float y, char z);
  那麼,調用函數的時候,實參 char z 先進棧,而後是 float y,最後是 int x,所以在內存中變量的存放次序是 x->y->z,所以,從理論上說,咱們只要探測到任意一個變量的地址,而且知道其餘變量的類型,經過指針移位運算,則總能夠順藤摸瓜找到其餘的輸入變量。
  下面是 <stdarg.h> 裏面重要的幾個宏定義以下:
typedef char* va_list;
void va_start ( va_list ap, prev_param ); /* ANSI version */
type va_arg ( va_list ap, type ); 
void va_end ( va_list ap ); 
va_list 是一個字符指針,能夠理解爲指向當前參數的一個指針,取參必須經過這個指針進行。
<Step 1> 在調用參數表以前,定義一個 va_list 類型的變量,(假設va_list 類型變量被定義爲ap);
<Step 2> 而後應該對ap 進行初始化,讓它指向可變參數表裏面的第一個參數,這是經過 va_start 來實現的,第一個參數是 ap 自己,第二個參數是在變參表前面緊挨着的一個變量,即「...」以前的那個參數;
<Step 3> 而後是獲取參數,調用va_arg,它的第一個參數是ap,第二個參數是要獲取的參數的指定類型,而後返回這個指定類型的值,而且把 ap 的位置指向變參表的下一個變量位置;
<Step 4> 獲取全部的參數以後,咱們有必要將這個 ap 指針關掉,以避免發生危險,方法是調用 va_end,他是輸入的參數 ap 置爲 NULL,應該養成獲取完參數表以後關閉指針的習慣。說白了,就是讓咱們的程序具備健壯性。一般va_start和va_end是成對出現。
 
例如 int max(int n, ...); 其函數內部應該如此實現:
#include <iostream.h> 
void fun(int a, ...) 
{ 
  int *temp = &a;
  temp++;
  for (int i = 0; i < a; ++i) 
  { 
    cout << *temp << endl; 
    temp++; 
  } 
}
int main() 
{ 
  int a = 1; 
  int b = 2; 
  int c = 3; 
  int d = 4; 
  fun(4, a, b, c, d); 
  system("pause"); 
  return 0; 
} 

 

Output:: 



4htm

3:獲取省略號指定的參數
  在函數體中聲明一個va_list,而後用va_start函數來獲取參數列表中的參數,使用完畢後調用va_end()結束。像這段代碼: 
void TestFun(char* pszDest, int DestLen, const char* pszFormat, ...) 
{ 
va_list args; 
va_start(args, pszFormat); //必定要「...」以前的那個參數
_vsnprintf(pszDest, DestLen, pszFormat, args); 
va_end(args); 
}

 

4.演示如何使用參數個數可變的函數,採用ANSI標準形式 
#include 〈stdio.h〉 
#include 〈string.h〉 
#include 〈stdarg.h〉 

/*函數原型聲明,至少須要一個肯定的參數,注意括號內的省略號*/ 
int demo( char, ... ); 
void main( void ) 
{ 
   demo("DEMO", "This", "is", "a", "demo!", ""); 
} 

/*ANSI標準形式的聲明方式,括號內的省略號表示可選參數*/ 
int demo( char msg, ... ) 
{ 
       /*定義保存函數參數的結構*/
   va_list argp; 
   int argno = 0; 
   char para; 
     /*argp指向傳入的第一個可選參數,msg是最後一個肯定的參數*/ 
   va_start( argp, msg ); 
   while (1) 
       { 
        para = va_arg( argp, char); 
           if ( strcmp( para, "") == 0 ) 
               break; 
           printf("Parameter #%d is: %s\n", argno, para); 
           argno++; 
} 
va_end( argp ); 
/*將argp置爲NULL*/
return 0; 
}

 

 以上是對va_start和va_end的介紹。blog

 

轉載於:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html內存

相關文章
相關標籤/搜索