C語(yǔ)言可變參數(shù)函數(shù)詳解示例
先看代碼
printf(“hello,world!”);其參數(shù)個(gè)數(shù)為1個(gè)。
printf(“a=%d,b=%s,c=%c”,a,b,c);其參數(shù)個(gè)數(shù)為4個(gè)。
如何編寫(xiě)可變參數(shù)函數(shù)呢?我們首先來(lái)看看printf函數(shù)原型是如何定義的。
在linux下,輸入man 3 printf,可以看到prinf函數(shù)原型如下:
SYNOPSIS
#include <stdio.h>
int printf(const char *format, ...);
后面的三個(gè)點(diǎn)...表示printf參數(shù)個(gè)數(shù)是不定的.
如何實(shí)現(xiàn)可變參數(shù)函數(shù)?
2. 編寫(xiě)可變函數(shù)準(zhǔn)備
為了編寫(xiě)可變參數(shù)函數(shù),我們通常需要用到<stdarg.h>頭文件下定義的以下函數(shù):
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
其中:
va_list是用于存放參數(shù)列表的數(shù)據(jù)結(jié)構(gòu)。
va_start函數(shù)根據(jù)初始化last來(lái)初始化參數(shù)列表。
va_arg函數(shù)用于從參數(shù)列表中取出一個(gè)參數(shù),參數(shù)類(lèi)型由type指定。
va_copy函數(shù)用于復(fù)制參數(shù)列表。
va_end函數(shù)執(zhí)行清理參數(shù)列表的工作。
上述函數(shù)通常用宏來(lái)實(shí)現(xiàn),例如標(biāo)準(zhǔn)ANSI形式下,這些宏的定義是:
typedef char * va_list; //字符串指針
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
使用宏_INTSIZEOF是為了按照整數(shù)字節(jié)對(duì)齊指針,因?yàn)閏調(diào)用協(xié)議下面,參數(shù)入棧都是整數(shù)字節(jié)(指針或者值)。
函數(shù)官方說(shuō)明,如果你看到英文就煩,可以自行忽略以下說(shuō)明。
va_start()
The va_start() macro initializes ap for subsequent use by va_arg() and
va_end(), and must be called first.
The argument last is the name of the last argument before the variable
argument list, that is, the last argument of which the calling function
knows the type.
Because the address of this argument may be used in the va_start()
macro, it should not be declared as a register variable, or as a func‐
tion or an array type.
va_arg()
The va_arg() macro expands to an expression that has the type and value
of the next argument in the call. The argument ap is the va_list ap
initialized by va_start(). Each call to va_arg() modifies ap so that
the next call returns the next argument. The argument type is a type
name specified so that the type of a pointer to an object that has the
specified type can be obtained simply by adding a * to type.
The first use of the va_arg() macro after that of the va_start() macro
returns the argument after last. Successive invocations return the
values of the remaining arguments.
If there is no next argument, or if type is not compatible with the
type of the actual next argument (as promoted according to the default
argument promotions), random errors will occur.
If ap is passed to a function that uses va_arg(ap,type) then the value
of ap is undefined after the return of that function.
va_end()
Each invocation of va_start() must be matched by a corresponding invo‐
cation of va_end() in the same function. After the call va_end(ap) the
variable ap is undefined. Multiple traversals of the list, each brack‐
eted by va_start() and va_end() are possible. va_end() may be a macro
or a function.
GNU給出的一個(gè)實(shí)例:
#include <stdio.h>
#include <stdarg.h>
void
foo(char *fmt, ...)
{
va_list ap;
int d;
char c, *s;
va_start(ap, fmt);
while (*fmt)
switch (*fmt++) {
case 's': /* string */
s = va_arg(ap, char *);
printf("string %s\n", s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("int %d\n", d);
break;
case 'c': /* char */
/* need a cast here since va_arg only takes fully promoted types */
c = (char) va_arg(ap, int);
printf("char %c\n", c);
break;
}
va_end(ap);
}
說(shuō)明:
va_start(ap, fmt);用于根據(jù)fmt初始化可變參數(shù)列表。
va_arg(ap, char *);用于從參數(shù)列表中取出一個(gè)參數(shù),其中的char *用于指定所取的參數(shù)的類(lèi)型為字符串。每次調(diào)用va_arg后,參數(shù)列表ap都會(huì)被更改,以使得下次調(diào)用時(shí)能得到下一個(gè)參數(shù)。
va_end(ap);用于對(duì)參數(shù)列表進(jìn)行一些清理工作。調(diào)用完va_end后,ap便不再有效。
以上程序給了我們一個(gè)實(shí)現(xiàn)printf函數(shù)的是思路,即:通過(guò)調(diào)用va_start函數(shù),來(lái)得到參數(shù)列表,然后我們一個(gè)個(gè)取出參數(shù)來(lái)進(jìn)行輸出即可。
3.實(shí)例
例如:對(duì)于printf(“a=%d,b=%s,c=%c”,a,b,c)語(yǔ)句;fmt的值為a=%d,b=%s,c=%c,調(diào)用va_start函數(shù)將參數(shù)a,b,c存入了ap中。注意到:fmt中的%為特殊字符,緊跟%后的參數(shù)指明了參數(shù)類(lèi)型.
因此我們的簡(jiǎn)易printf函數(shù)如下:
#include <stdio.h>
#include <stdarg.h>
void
myprintf(char *fmt, ...)
{
va_list ap;
int d;
double f;
char c;
char *s;
char flag;
va_start(ap,fmt);
while (*fmt){
flag=*fmt++;
if(flag!='%'){
putchar(flag);
continue;
}
flag=*fmt++;//記得后移一位
switch (flag)
{
case 's':
s=va_arg(ap,char*);
printf("%s",s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("%d", d);
break;
case 'f': /* double*/
d = va_arg(ap,double);
printf("%d", d);
break;
case 'c': /* char*/
c = (char)va_arg(ap,int);
printf("%c", c);
break;
default:
putchar(flag);
break;
}
}
va_end(ap);
}
int main(){
char str[10]="linuxcode";
int i=1024;
double f=3.1415926;
char c='V';
myprintf("string is:%s,int is:%d,double is:%f,char is :%c",str,i,f,c);
}
從上面我們可以知道可變參數(shù)函數(shù)的編寫(xiě),必須要傳入一個(gè)參數(shù)fmt,用來(lái)告訴我們的函數(shù)怎樣去確定參數(shù)的個(gè)數(shù)。我們的可變參數(shù)函數(shù)是通過(guò)自己解析這個(gè)參數(shù)來(lái)確定函數(shù)參數(shù)個(gè)數(shù)的。
比如,我們編寫(xiě)一個(gè)求和函數(shù),其函數(shù)實(shí)現(xiàn)如下:
int sum(int cnt,...){
int sum=0;
int i;
va_list ap;
va_start(ap,cnt);
for(i=0;i<cnt;++i)
sum+=va_arg(ap,int);
va_end(ap);
return sum;
}
總結(jié)一下就是:通過(guò)va_start初始化參數(shù)列表(也就能得到具體的參數(shù)個(gè)數(shù)了),然后使用va_arg函數(shù)從參數(shù)列表中取出你想要的參數(shù),最后調(diào)用va_end執(zhí)行清理工作。
欄 目:C語(yǔ)言
下一篇:C/C++產(chǎn)生指定范圍和不定范圍隨機(jī)數(shù)的實(shí)例代碼
本文標(biāo)題:C語(yǔ)言可變參數(shù)函數(shù)詳解示例
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/3911.html
您可能感興趣的文章
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用函數(shù)刪除字符
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)式函數(shù)庫(kù)
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)數(shù)怎么表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段函數(shù)
- 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排序法函數(shù)
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段函數(shù)
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎么打出三角函數(shù)的值
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求階乘


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 04-02jquery與jsp,用jquery
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-10delphi制作wav文件的方法
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什