1. 程式人生 > 程式設計 >C語言中可變引數的使用方法示例

C語言中可變引數的使用方法示例

前言

在C語言程式編寫中我們使用最多的函式一定包括printf以及很多類似的變形體。這個函式包含在C庫函式中,定義為 int printf( const char* format,...);

除了一個格式化字串之外還可以輸入多個可變參量,如:

   printf("%d",i);
   printf("%s",s);
   printf("the number is %d,string is:%s",i,s);

格式化字串的判斷本章暫且不論,下面分析一下可變引數的實現細節。

一,簡單例項

int simple(int num,...)
{
  int i,result=0;
  va_list vl;  //va_list指標,用於va_start取可變引數,為char*
  va_start(vl,num);  //取得可變引數列表中的第一個值
  printf("num:%d,vl:%d\n",num,*vl);
  for (i = 0; i < (num-1); i++)//這裡num表示可變引數列表中有多少個引數 
 {
  result = va_arg(vl,int);//這裡把vl往後跳過4個位元組(sizeof(int)大小)指向下一個引數,返回的是當前引數(而非下
一個引數) 
  printf("in for result:%d,*vl:%d\n",result,*vl);//這裡列印下,可以看出,vl總是指向result後面的那個引數 
 }
 va_end(vl);//結束標誌 

 return result;

}
int main(int argc,char **argv)
{
  int num = argc;
  int i = 0;
  simple(5,1,2,3,4,5);

  return 1;

}

執行結果如下:

book@book-desktop:~/own$ ./varlist
num:5,vl:1
in for result:1,*vl:2
in for result:2,*vl:3
in for result:3,*vl:4
in for result:4,*vl:5

二.相關API介紹

可變引數列表的實現是由幾個巨集組成的,在檔案include/stdarg.h中:

va_list 定義某個變數,核心中的定義:

  typedef char *va_list;//字元指標型別 

va_start(ap,type) 開始獲取可變引數列表中的第一個引數(...裡面的第一個),也就是跳過第一個引數(即num):

#ifndef __sparc__
#define va_start(AP,LASTARG)             \
 (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))//ap指向下一個引數,lastarg不變
#else
#define va_start(AP,LASTARG)             \
 (__builtin_saveregs (),\
 AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG))) //跳過下第一個引數,指向第二個引數記憶體地址
#endif

//對type向上取整 取int的整 4,然後乘上int整型4的倍數
#define __va_rounded_size(TYPE) \
 (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))

va_arg(args,int) 迴圈獲取到可變引數列表中的引數,args指向下一個引數地址,返回的則是當前引數地址

// first=va_arg(args,int)
#define va_arg(AP,TYPE)            \//ap指向下一個型別的引數
 (AP += __va_rounded_size (TYPE),\//返回ap - sizeof(type)引數,即前一個引數
 *((TYPE *) (AP - __va_rounded_size (TYPE))))

//對type向上取整 取int的整 4,然後乘上int整型4的倍數
#define __va_rounded_size(TYPE) \
 (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))

最後一個va_end(ap)結束標誌,可能只是在程式中作為一個可變引數列表的結束標誌而已(stdarg.h裡面只是僅僅定義了下,沒有實現的程式碼部分)。

三.可變參事應用是注意事項

因為va_start,va_arg,va_end等定義成巨集,所以它顯得很愚蠢,可變引數的型別和個數完全在該函式中由程式程式碼控制,它並不能智慧地識別不同引數的個數和型別.有人會問:那麼printf中不是實現了智慧識別引數嗎?那是因為函式printf是從固定引數format字串來分析出引數的型別,再呼叫va_arg的來獲取可變引數的.也就是說,你想實現智慧識別可變引數的話是要通過在自己的程式裡作判斷來實現的.另外有一個問題,因為編譯器對可變引數的函式的原型檢查不夠嚴格,對程式設計查錯不利.

如將simple可變引數該成char型指標,若存在空指標在會產生coredump

void simple(int i,...)
{
  va_list arg_ptr;
  char *s=NULL;

  va_start(arg_ptr,i);
  s=va_arg(arg_ptr,char*);
  va_end(arg_ptr);
  printf("%d %s\n",s);
  return;
}

可變引數為char*型,當我們忘記用兩個引數來呼叫該函式時,就會出現core dump(Unix) 或者頁面非法的錯誤(window平臺).但也有可能不出錯,但錯誤卻是難以發現,不利於我們寫出高質量的程式.

總結

到此這篇關於C語言中可變引數的使用方法示例的文章就介紹到這了,更多相關C語言可變引數用法內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!