對C語言中va_list,va_start,va_arg和va_end的一點理解


  這幾個函數和變量是針對可變參數函數的,什么是可變參數函數呢,最經典的莫過於printf和scanf,這兩個函數的聲明如下:

1 int printf(const char *format, ...);
2 
3 int scanf(const char *format, ...);

  這兩個函數聲明中省略號(...)表示的就是任意個數的參數,可變參數函數就是輸入的參數的個數是可變的,那么這個具體是怎么實現的呢?

 

  要了解這個是怎么實現,首先我們就要先理解一點,參數是如何傳遞給函數的。眾所周知,函數的數據是存放於棧中的,那么給一個函數傳遞傳遞參數的過程就是將函數的參數從右向左逐次壓棧,例如:

  func(int i, char c, doube d)

  這個函數傳遞參數的過程就是將d,c,i逐次壓到函數的棧中,由於棧是從高地址向低地址擴展的,所以d的地址最高,i的地址最低。

 

  理解了函數傳遞參數的過程,再來說一下va_list的原理,通常,可變參數的代碼是這么寫的:

1 void func(char *fmt, ...)
2 {
3      va_list ap;
4 
5      va_start(ap, fmt);
6      va_arg(ap, int);
7      va_end(va);      
8 }

  這里ap其實就是一個指針,指向了參數的地址。

  va_start()所做的就是讓ap指向函數的最后一個確定的參數(聲明程序中是fmt)的下一個參數的地址。

  va_arg()所做的就是根據ap指向的地址,和第二個參數所確定的類型,將這個參數的中的數據提取出來,作為返回值,同時讓ap指向下一個參數。

  va_end()所做的就是讓ap這個指針指向0。

 

  關於這三個參數實現的宏可以參看下面的實現:

1 // 使ap指向第一個可變參數的地址
2 #define  va_start(ap,v)     ( ap = (va_list)&v + _INTSIZEOF(v) )
3 
4 // 使ap指向下一個可變參數,同時將目前ap所指向的參數提取出來並返回
5 #define  va_arg(ap,t)       ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
6 
7 //  銷毀ap 
8 #define  va_end(ap)         ( ap = (va_list)0 ) 

 

參考文章:

1. 詳解 C語言可變參數 va_list和_vsnprintf及printf實現


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM