va list C語言中的可變引數

2021-05-21 13:37:58 字數 1856 閱讀 1422

c語言中有些函式使用可變引數,比如常見的int printf( const char* format, ...),第乙個引數format是固定的,其餘的引數的個數和型別都不固定。但c又無法用面相物件的函式過載的概念。

不過好在c語言中定義了va_list, va_start( ), va_arg( ), va_end( ) 這樣一組巨集來處理可變引數問題。

這組巨集在stdarg.h標頭檔案中定義,但是由於1)硬體平台的不同 2)編譯器的不同,所以定義的巨集也有所不同,下面以vc++中stdarg.h裡x86平台的巨集定義為例(linux環境中在stdarg.h裡發現它將這組巨集定義為gcc的內建函式了。__builtin_)

/typedef char * va_list;

#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 )

/(一)

_intsizeof(n)巨集是為了考慮那些記憶體位址需要對齊的系統,從巨集的名字來應該是跟sizeof(int)對齊。一般的sizeof(int)=4,也就是引數在記憶體中的位址都為4的倍數。比如,如果sizeof(n)在1-4之間,那麼_intsizeof(n)=4;如果sizeof(n)在5-8之間,那麼_intsizeof(n)=8。

(二)為了能從固定引數依次得到每個可變引數,va_start, va_arg充分利用下面兩點:

1. c語言在函式呼叫時,先將最後乙個引數壓入棧

2. x86平台下的記憶體分配順序是從高位址記憶體到低位址記憶體

高位位址

第n個引數

。。。第二個引數 (第乙個可變引數)

第乙個引數 (固定引數)

低位位址

由此可見,v是第乙個固定引數( 可變引數函式的第乙個引數應該是固定引數,第二個引數開始才是可變的)在記憶體中的位址,在呼叫va_start後,ap指向第乙個可變引數。這個巨集的作用就是在v的記憶體位址上增加v所佔的記憶體大小,這樣就得到了第乙個可變引數的位址。

接下來,可以這樣設想,如果我能確定這個可變引數的型別,那麼我就知道了它占用了多少記憶體,依葫蘆畫瓢,我就能得到下乙個可變引數的位址。

(三)

讓我再來看看va_arg,它先ap指向下乙個可變引數,然後減去當前可變引數的大小即得到當前可變引數的記憶體位址,再做個型別轉換,返回它的值。以t是int類為例:

j =  va_arg(ap,int)  =  *(int*)( ( ap += _intsizeof(int) )-_intsizeof(int) )

首先ap+=sizeof(int),已經ap指向下乙個引數的位址了.  然後返回ap-sizeof(int)的int*指標,這正是之前乙個引數在堆疊裡的位址.然後用*取得這個位址的內容(引數值)賦給j.

要確定每個可變引數的型別,有兩種做法:要麼都是預設的型別,要麼就在固定引數中包含足夠的資訊讓程式可以確定每個可變引數的型別。比如,printf,程式通過分析format字串就可以確定每個可變引數大型別。

(四)最後要說的是va_end巨集的意思,x86平台定義為ap=(char*)0;使ap不再指向堆疊,而是跟null一樣.有些直接定義為((void*)0),這樣編譯器不會為va_end產生**

舉例:

#include

#include

void va_fun(int start,...)

return;

}main()

valist c語言可變引數巨集

va list 是c語言中解決變參問題的一組巨集。1.api介紹 標頭檔案 cpp view plain copy print?include 下面是實現變參函式的一組巨集 macro cpp view plain copy print?void va start va list ap,last t...

C語言中的可變引數

1 需要標頭檔案 include 2 函式定義 void logcmd int arg0,void logcmd char arg0,3 解析 i 數字型別 void logcmd int n,其中n表示引數的個數,n之後才是真正的引數。呼叫如 logcmd 0 logcmd 1,9 logcmd ...

va list C語言引數列表

va list是乙個巨集,由va start和va end界定。typedef char va list void va start va list ap,prev param type va arg va list ap,type void va end va list ap 其中,va list...