1. 程式人生 > >關於C中可變長參數

關於C中可變長參數

函數參數 sta 問題 erl 必須 fin 用戶 保存 tst

前言

可變長參數指函數的參數個數在調用時才能確定的函數參數。基本上各種語言都支持可變長參數,在特定情形下,可變長參數使用起來非常方便。c語言中函數可變長參數使用“...”來表示,同時可變長參數只能位於固定參數的後面,固定參數的個數至少為1。只要學習過c語言的,應該都知道printf函數,並且見識到了其強大的功能——事實上,迄今為止,我仍認為這是c函數庫中最牛逼的函數之一。

一、一個簡單的例子

  1. #include <string>
  2. #include <stdio>
  3. ///拼接字符串
  4. char * JointStr(int Count, ...)
  5. {
  6. char * pszBuff = new char[100];
  7. ::memset(pszBuff, 0, 100);
  8. va_list vl;
  9. va_start(vl, Count);
  10. for(int i = 0; i < Count; i++)
  11. {
  12. strcat(pszBuff, va_arg(vl, char *));
  13. }
  14. return pszBuff;
  15. }
  16. void main()
  17. {
  18. char * pszStr = JointStr(3, "abc", "123", "!@#");
  19. printf("%s", pszStr);
  20. }

  執行後,輸出:abc123!@#

函數JointStr的功能是指定個數的字符串拼接起來,返回拼接後的字符串的指針。參數Count是字符串的個數,後面跟可變長參數,使用時應該跟Count個char*型參數。使用時,可以隨意指定個數。(該例子只是用來說明問題,實際使用時不會用這個函數,可以使用標準庫函數中的sprintf函數)。

二、可變長參數的使用方法

首先,必須弄清楚一下三個宏定義:

  • va_arg
  • va_start
  • va_end

以及一個類型:va_list

從c函數庫中的頭文件中可以看到va_list的定義:

typedef char *  va_list;

也就是說它就是一個指針,那麽該指針指向什麽地方呢? 這就是va_start的作用了。首先看看這三個宏定義的申明:

  1. #define va_start(ap,v)
  2. #define va_arg(ap,t)
  3. #define va_end(ap)

va_start有兩個參數:第一個ap應該填寫va_list,第二個v應該填寫函數參數列表中(可以認為傳給函數的參數是一個列表,一個接一個)的某個參數,例如例子中的Count。其作用是將ap指向函數參數列表中的參數v的位置(msdn是這樣說的,我覺得應該指向參數列表中的參數v的下一個參數的開始地址)。

va_end作用是將ap設置為NULL。

va_arg(ap,t)有兩個參數:第一個是va_list,第二個是參數類型。其作用是從ap開始取一個t型的值返回,並且自動將ap指向下一個參數。所以如果t即參數類型寫錯了,例如將char*寫成char了,本來要取4個字節,結果只取了一個字節,ap本來要向後面移動4個字節,結果只移動了一個字節,後面的數據就全錯了。同時,如果你多取了一次參數,將報內存越界錯誤,所以使用可變長參數,前面一般都會傳一個參數來指定參數的個數。

使用可變長參數的步驟:

  1. 聲明va_list變量
  2. 使用va_start指定可變長參數的位置
  3. 使用va_arg來獲取參數值
  4. 可選,使用va_end將va_list清零

三、va_list類型作為參數

在c標準庫中有一個函數vsprintf,聲明如下:

int __cdecl vsprintf(char *_DstBuf, char * _Format, va_list _ArgList);

其第三個參數為va_list類型,我們可以在這樣使用:

char* GetFormatStr(char* format, ...)

{
char *pszBuff = new char[256];
va_list vl;
va_start(vl,format);
vsprintf(pszBuff, format, vl);
return pszBuff;
}
void main()
{
char * str = GetFormatStr("%s is %d year old.", "frank", 25);
printf("%s", str);
}

將輸出:frank is 25 year old.

結束語

我們可以認為,我們調用可變長參數的函數時,傳遞給函數的參數是在堆棧中保存為一個緊挨一個的列表。獲取參數的唯一方法就是通過參數列表的指針,取一個參數,移動一個參數長度的指針,實際上如何取參數完全掌握在用戶手中,用戶應當小心應對。

原文鏈接:

https://blog.csdn.net/frank_liuxing/article/details/18000825

關於C中可變長參數