可變引數個數的函式

2021-06-23 08:41:09 字數 4361 閱讀 6195

type vafunction(typearg1,typearg2,…);

引數可以分為兩部分:個數確定的固定引數和個數可變的可選引數。函式至少需要乙個固定引數,固定引數的宣告和普通函式一樣;可選引數由於個數不確定,宣告時用"..."表示。固定引數和可選引數公同構成乙個函式的引數列表。

  標準c/c++包含標頭檔案stdarg.h,該標頭檔案中定義了如下三個巨集:

void va_start(va_list arg_ptr,prev_param);/*ansiversion*/

type va_arg(va_list arg_ptr,type); 

void va_end(va_list arg_ptr); 

在這些巨集中,va 就是variableargument(可變引數)的意思;

arg_ptr 是指向可變參數列的指標;

prev_param 指可變參數列的前乙個固定引數;

type 為可變引數的型別。

va_list 也是乙個巨集,其定義為typedef char* va_list,實質上是一char 型指標。

char 型指標的特點是++、--操作對其作用的結果是增1 和減1(因為sizeof(char)為1)。

 va_start 巨集可以取得可變參數列的首指標,這個巨集的定義為:

#define va_start(ap,v)(ap=(va_list)&v+_intsizeof(v))

#define _intsizeof(n)  ((sizeof(n)+sizeof(int)-1)&~(sizeof(int)-1))

va_start(arg_ptr,argn):使引數列表指標arg_ptr 指向函式引數列表中的第乙個可選引數,說明:argn 是位於第乙個可選引數之前的固定引數,(或者說,最後乙個固定引數;…之前的乙個引數),函式引數列表中引數在記憶體中的順序與函式宣告時的順序是一致的。

如果有一va 函式的宣告是void va_test(chara,charb,charc,…),則它的固定引數依次是a,b,c,最後乙個固定引數argn 為c,因此就是va_start(arg_ptr,c)。va_arg 巨集的意思則指取出當前arg_ptr 所指的可變引數並將ap 指標指向下一可變引數,其原型為:

#define va_arg(list,mode)  ((mode*)(list=(char*)((((int)list+(__builtin_alignof(mode)<=4?3:7))&(__builtin_alignof(mode)<=4?-4:-8))+sizeof(mode))))[-1]

va_end 巨集被用來結束可變引數的獲取,其定義為:

#define va_end(list) 

可以看出,va_end(list)實際上被定義為空,沒有任何真實對應的**,用於**對稱,與va_start 對應。

舉例說明:

#include 

#include //包含些標頭檔案

//第乙個引數為固定引數,一般含有可變引數個數的資訊,第二個引數起就是可變引數拉

void variablefunc(int prev_param,...)

va_list arg_ptr; //可變參數列的首指標

va_start(arg_ptr,prev_param);//va_start 巨集可以取得可變參數列的首指標

printf("prev_param 的值說明可變引數的個數:%d\n",prev_param);

for(int i=0;i int paramvalue; //儲存可變引數的值(函式的第乙個引數是固定引數,第二個引數起才是可變引數

 paramvalue=va_arg(arg_ptr,int);//va_arg 巨集的意思則指取出當前arg_ptr所指的可變引數並將ap 指標指向下一可變引數

 printf("這是第%d 個可變引數,值:%d, 型別:int\n",i+1,paramvalue);

va_end(arg_ptr);//執行清理工作

void main()

//第乙個引數3 表示將有三個可變引數,分別是8,9,19

variablefunc(3,8,9,10);

#include 

#include //包含些標頭檔案

#include 

using namespace std;

//模仿printf 函式

void myprint(char* prev_param,...)

int j=0;

va_list arg_ptr;//可變參數列的首指標

va_start(arg_ptr,prev_param);//va_start 巨集可以取得可變參數列的首指標

string formatstr(prev_param);//儲存格式化的字串

int insertpos;

while(-1!=(insertpos=formatstr.find("%")))

 if(formatstr[insertpos+1]=='d')//%號後是'd'就轉為字元再插入formatstr

 char buf[15];

 int intvalud=va_arg(arg_ptr,int);//從可變引數列表中獲得資料

 itoa(intvalud,buf,10); //int 轉string 並儲存在buf

 formatstr.erase(insertpos,2); //擦除兩個字元%d

 formatstr.insert(insertpos,buf);//插入int 值到formatstr

 else if(formatstr[insertpos+1]=='s')

 formatstr.erase(insertpos,2);

 formatstr.insert(insertpos,va_arg(arg_ptr,char*));

printf("%s\n",formatstr.c_str());

va_end(arg_ptr);//執行清理工作

void main()

myprint("showyouhow%s%swork%d","printf","function",88);

#include  

#include  

struct  t_progs{ 

int x; 

int y; 

void func(t_progs *tprogs,...) 

int total = 0; 

va_list ap; 

t_progs *p; 

va_start(ap, tprogs); 

p = tprogs; 

printf("x[%d]=%d\n",total,p->x); 

printf("y[%d]=%d\n",total,p->y); 

total++; 

while (p = (va_arg(ap,t_progs*))) 

 printf("x[%d]=%d\n",total,p->x); 

 printf("y[%d]=%d\n",total,p->y); 

 total ++; 

va_end(ap); 

printf("引數個數:%d\n",total); 

void main(void) 

t_progs test1,test2; 

test1.x = 1;test2.x = 3; 

test1.y = 2;test2.y = 4; 

func(&test1,&test2,null); 

怎樣得到可變引數個數?歸納起來有三種辦法: 

1.函式的第乙個引數,指定後續的引數個數,如func(int num,...) 

2.根據隱含引數,判斷引數個數,如printf 系列的,通過字串中%的個數判斷

3.特殊情況下(如引數都是不大於0xffff 的int),可以一直向低處訪問堆疊,直到返回位址。

引數個數可變的函式

今天突然想起引數個數可變的函式,然後想了下,覺得自己還真不太了解它,遂決定弄清楚。1.如何取得可變引數 比如 void f int fixpara1,char p char fixpara1 取得固定引數位址 cout int p 為什麼p 4可以取到第乙個可變引數呢?因為引數在函式被呼叫前,會逐個...

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...

swift定義引數個數可變的函式

在oc中,當乙個功能豐富的類對外暴露介面時,在.件中往往會提供一系列的api,引數由少到多。但是在.m檔案的實現中,往往都是利用乙個通用的實現。例如 宣告 int addnuma int numa numb int numb int addnuma int numa numb int numb nu...