天天看點

基礎:va_start和va_end使用詳解

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

  介紹va_start和va_end這兩個宏之前,先看一下c中傳遞函數的參數時的用法和原理:

1、在c中,當我們無法列出傳遞函數的所有實參的類型和數目時,可以用省略号指定參數表

這種方式和我們以前認識的不大一樣,但我們要記住這是c中一種傳參的形式,在後面我們就會用到它。

2、函數參數的傳遞原理

  函數參數是以資料結構棧的形式存取,<b>從右至左入棧</b>。

  舉個例子如下:void func(int x, float y, char z);

  那麼,調用函數的時候,實參 char z 先進棧,然後是 float y,最後是 int x,是以在記憶體中變量的存放次序是 x-&gt;y-&gt;z,是以,從理論上說,我們隻要探測到任意一個變量的位址,并且知道其他變量的類型,通過指針移位運算,則總可以順藤摸瓜找到其他的輸入變量。

  下面是 &lt;stdarg.h&gt; 裡面重要的幾個宏定義如下:

va_list 是一個字元指針,可以了解為指向目前參數的一個指針,取參必須通過這個指針進行。

1&gt; 在調用參數表之前,<b>定義一個 va_list 類型的變量</b>,(假設va_list 類型變量定義為ap);

2&gt; 應該對ap 進行初始化,讓它<b>指向</b>"<b>可變參數表</b>"裡面的<b>第一個參數</b>,通過<b>調用va_start</b>來實作的,第一個參數是 ap 本身,第二個參數是在"變參表"前面緊挨着的變量即para,也就是“...”之前的那個參數;<b>可變參數表就是“...”,簡稱變參表</b>。

3&gt; 若想<b>擷取參數</b>,<b>調用va_arg</b>,它的第一個參數是ap,第二個參數是要擷取參數的類型,然後傳回此類型的值,<b>這兩個類型必須一緻</b>,并把 ap 的位置指向"變參表"的下一個變量位置;

4&gt; 擷取所有的參數之後,有必要<b>将這個 ap 指針關掉</b>,以免發生危險,<b>調用va_end</b>方法将輸入參數 ap 置為 null,應該養成擷取完參數表之後關閉指針的習慣。

例如 int max(int n, ...); 其函數内部應該如此實作:

3、擷取省略号指定的參數

  在函數體中聲明一個va_list,然後用va_start函數來擷取參數清單中的參數,使用完畢後調用va_end()結束。像這段代碼:

4、示範如何使用參數個數可變的函數,采用ansi标準形式

<b>函數原型聲明,至少需要一個确定的參數</b>,注意括号内的省略号

以上是對va_start和va_end的介紹。

繼續閱讀