精通Unix下C語言編程與項目實踐之二
函數的變長參數
作者:朱雲翔,胡平
5.4 函數的變長參數
文件的格式化輸入輸出函數都支持變長參數。定義時,變長參數列表通過省略號“…”表示,因此,具有變長參數列表的函數定義格式為:
type 函數名(參數1, 參數2, 參數n, ...);
其中type為函數的返回值類型,參數1~參數n為定長參數,“...”代表變長參數,注意“...”必須定義在參數的最右端。如下例:
int printf(const char *format, ...);
int mysum(...);
5.4.1. 變長參數的使用
Unix的變長參數通過va_list對象實現,定義在文件“stdarg.h”中,變長參數的應用模板如代碼5-15所示:
代碼5-15 變長參數代碼模板
#include <stdarg.h>
function (parmN, ...)
va_list pvar;
……………………………
va_start (pvar, parmN);
while()
{
……………………
f = va_arg (pvar, type);
……………………
}
va_end (pvar);
1. va_list pvar
申明va_list數據類型變量pvar,該變量訪問變長參數列表中的參數。
2. va_start(pvar, parmN)
宏va_start初始化變長參數列表。pvar是va_list型變量,在步驟1中定義,記載列表中的參數信息。parmN是省略號“...”前的一個參數名,va_start根據此參數,判斷參數列表的起始位置,如:
例1. 函數:function(parmN, …)
答:va_start(pvar, parmN);
例2. 函數:int mysum(int i, int j, …)
答:va_start(pvar, j);
3. va_arg(pvar, type)
獲取變長參數列表中參數的值。pvar是步驟1中定義的va_list型變量,type為參數值的類型,也是宏va_arg返回數值的類型,如:
va_arg(pvar, int); /* 將參數列表中的當前參數值轉化為int型返回 */
va_arg(pvar, float); /* 將參數列表中的當前參數值轉化為float型返回*/
宏va_arg執行完畢後自動更改對象pvar,將其指向下一個參數。
4. va_end(pvar)
關閉本次對變長參數列表的訪問。
實例
設計函數mysum,計算輸入參數的和並返回結果。源程序如代碼5-16所示:
代碼5-16 變長參數函數實例節自/code/chapter5/mysum.c)
#include <stdarg.h>
int mysum(int i, ...) /* 參數i表明變長參數的個數 */
{
int r=0, j=0;
va_list pvar;
va_start(pvar, i);
for (j=0; j<i; j++)
{
r += va_arg(pvar, int);
}
va_end(pvar);
return(r);
}
void main()
{
printf("sum(1,4)=%d\n", mysum(1, 4));
printf("sum(2,4,8)=%d\n", mysum(2, 4, 8));
}
編譯與運行代碼5-16:
# make mysum
cc -O -o mysum mysum.c
# ./mysum
sum(1,4)=4
sum=(2,4,8)=12
5.4.2 變長參數的傳遞
上一節講述了如何創建具有變長參數的函數和如何讀取變長參數,其操作都在函數內完成,本節將講述把變長參數列表整體作為參數傳遞給其他函數的方法。
變長參數傳遞的函數族如下:
#include <stdarg.h>
int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
這些函數完全等價於格式化輸出函數,只是在形式上采用固定參數代替變長參數,這樣描述的函數更加緊湊,這些函數常應用於變長參數函數內部的功能實現。
實例
設計函數“int PrintLog(FILE* stream, const char* pformat, ...)”,它按照字符串format的內容,控制後繼參數的數量和格式,並在文件流stream中輸出。源程序如代碼5-17所示:
代碼5-17 傳遞變長參數實例節自/code/chapter5/print1.c)
#include <stdarg.h>
#include <stdio.h>
int PrintLog(FILE* pfile, const char * pformat, ...)
{
va_list _va_list;
char szBuf[1024];
if (pformat == NULL || pfile == NULL) return -1; /* 判斷指針是否正確*/
va_start(_va_list, pformat); /* 初始化變長參數列表 */
vsprintf(szBuf, pformat, _va_list); /* 傳遞變長參數 */
va_end(_va_list); /* 結束使用變長參數列表 */
fputs(szBuf, pfile); /* 輸出到文件流 */
return 0;
}
void main()
{
PrintLog(stderr, "[%s][%s][%d][%c]\n", "This", "Is", 5, 'a');
PrintLog(stderr, "Error[%p][%.2f][%X]\n", NULL, 3.123, 100);
}
編譯與運行代碼5-17:
# make print1
cc -O print1.c -o print1
# ./print1
[This][Is][5][a]
Error[00000000][3.12][64]
實踐經驗】對於指針類型的參數,最好在函數入口處判斷其是否為空,以免空指針引用錯誤。如代碼5-17中黑體部分。
相關文章:
封面 前言 目錄 策劃 作者
動態庫 變長參數 文件鎖本文出自 “編程浪子朱雲翔” 博客,請務必保留此出處http://zhuyunxiang.blog.51cto.com/653596/129767