標籤:des io os 使用 ar for 檔案 資料 sp
現在先用一個使用過程講解一下:
◎用法:
func( Type para1, Type para2, Type para3, … )
{
/****** Step 1 ******/
va_list ap;
va_start( ap, para3 ); //一定要“…”之前的那個參數 ,而且這個參數不能使參考型別,因為參考型別不能根據其地址擷取後面參數的地址
/****** Step 2 ******/
//此時ap指向第一個可變參數
//調用va_arg取得裡面的值
Type xx = va_arg( ap, Type );
//Type一定要相同,如:
//char *p = va_arg( ap, char *);
//int i = va_arg( ap, int );
//如果有多個參數繼續調用va_arg
/****** Step 3 ******/
va_end(ap); //For robust!
}
然後寫個小程式,大家看看就明白了stdarg.h的用法了
#include <iostream>#include <stdarg.h>const int N=5;using namespace std;void Stdarg(int a1,…){ va_list argp; int i; int ary[N]; va_start(argp,a1); ary[0]=a1; for(i=1;i< N;i++) ary[i]=va_arg(argp,int); va_end(argp); for(i=0;i< N;i++) cout<<ary[i]<<endl;}void main(){ Stdarg(5,12,64,34,23);}
最後我們來分析一下stdarg.h這個標頭檔(呵呵,本人也是看的不太懂)
typedef char * va_list;
#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) – _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )
va_list argptr;
C語言的函數是從右向左壓入堆棧的,調用va_start後,
按定義的宏運算,_ADDRESSOF得到v所在的地址,然後這個
地址加上v的大小,則使ap指向第一個可變參數:
棧底 高地址
| …….
| 函數返回地址
| …….
| 函數最後一個參數
| ….
| 函數第一個可變參數 <–va_start後ap指向
| 函數最後一個固定參數
| 函數第一個固定參數
棧頂 低地址
然後,用va_arg()取得類型t的可變參數值, 先是讓ap指向下一個參數:
ap += _INTSIZEOF(t),然後在減去_INTSIZEOF(t),使得運算式結果為
ap之前的值,即當前需要得到的參數的地址,強制轉換成指向此參數的
類型的指標,然後用*取值
最後,用va_end(ap),給ap初始化,保持健壯性。
example:(chenguiming)
#include <stdio.h>
#include <ctype.h>
#include<stdlib.h>
#include <stdarg.h>
int average( int first, … ) //變參數函數,C++裡也有
{
int count=0,i=first,sum=0;
va_list maker; //va_list 類型資料可以儲存函數的所有參數,做為一個列表一樣儲存
va_start(maker,first); //設定列表的起始位置
while(i!=-1)
{
sum+=i;
count++;
i=va_arg(maker,int);//返回maker列表的當前值,並指向列表的下一個位置
}
return sum/count;
}
void main(void)
{
printf( "Average is: %d\n", average( 2, 3, 4,4, -1 ) );
}
Linux下的stdarg.h
#ifndef _STDARG_H
#define _STDARG_H
typedef char *va_list; /* 定義va_list 是一個字元指標類型*/
/* Amount of space required in an argument list for an arg of type TYPE.
TYPE may alternatively be an expression whose type is used. */
/* 下面給出了類型為TYPE 的arg 參數列表所要求的空間容量。
TYPE 也可以是使用該類型的一個運算式 */
// 下面這句定義了取整後的TYPE 類型的位元組長度值。是int 長度(4)的倍數。
#define __va_rounded_size(TYPE) \
(((sizeof (TYPE) + sizeof (int) – 1) / sizeof (int)) * sizeof (int))
// 下面這個函數(用宏實現)使AP 指向傳給函數的可變參數表的第一個參數。
// 在第一次調用va_arg 或va_end 之前,必須首先調用該函數。
// 17 行上的__builtin_saveregs()是在gcc 的庫程式libgcc2.c 中定義的,用於儲存寄存器。
// 它的說明可參見gcc 手冊章節“Target Description Macros”中的
// “Implementing the Varargs Macros”小節。
#ifndef __sparc__
#define va_start(AP, LASTARG) \
(AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#else
#define va_start(AP, LASTARG) \
(__builtin_saveregs (), \
AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#endif
// 下面該宏用於被調用函數完成一次正常返回。va_end 可以修改AP 使其在重新調用
// va_start 之前不能被使用。va_end 必須在va_arg 讀完所有的參數後再被調用。
void va_end (va_list); /* Defined in gnulib *//* 在gnulib 中定義 */
#define va_end(AP)
// 下面該宏用於擴充運算式使其與下一個被傳遞參數具有相同的類型和值。
// 對於預設值,va_arg 可以用字元、無符號字元和浮點類型。
// 在第一次使用va_arg 時,它返回表中的第一個參數,後續的每次調用都將返回表中的
// 下一個參數。這是通過先訪問AP,然後把它增加以指向下一項來實現的。
// va_arg 使用TYPE 來完成訪問和定位下一項,每調用一次va_arg,它就修改AP 以指示
// 表中的下一參數。
#define va_arg(AP, TYPE) \
(AP += __va
_rounded_size (TYPE), \
*((TYPE *) (AP – __va_rounded_size (TYPE))))
#endif /* _STDARG_H */
使用stdarg.h實現可變長度參數