C說話可變參數函數詳解示例。本站提示廣大學習愛好者:(C說話可變參數函數詳解示例)文章只能為提供參考,不一定能成為您想要的結果。以下是C說話可變參數函數詳解示例正文
先看代碼
printf(“hello,world!”);其參數個數為1個。
printf(“a=%d,b=%s,c=%c”,a,b,c);其參數個數為4個。
若何編寫可變參數函數呢?我們起首來看看printf函數原型是若何界說的。
在linux下,輸出man 3 printf,可以看到prinf函數原型以下:
SYNOPSIS
#include <stdio.h>
int printf(const char *format, ...);
前面的三個點...表現printf參數個數是不定的.
若何完成可變參數函數?
2. 編寫可變函數預備
為了編寫可變參數函數,我們平日須要用到<stdarg.h>頭文件下界說的以下函數:
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是用於寄存參數列表的數據構造。
va_start函數依據初始化last來初始化參數列表。
va_arg函數用於從參數列表中掏出一個參數,參數類型由type指定。
va_copy函數用於復制參數列表。
va_end函數履行清算參數列表的任務。
上述函數平日用宏來完成,例如尺度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是為了依照整數字節對齊指針,由於c挪用協定上面,參數入棧都是整數字節(指針或許值)。
函數官方解釋,假如你看到英文就煩,可以自行疏忽以下解釋。
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給出的一個實例:
#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);
}
解釋:
va_start(ap, fmt);用於依據fmt初始化可變參數列表。
va_arg(ap, char *);用於從參數列表中掏出一個參數,個中的char *用於指定所取的參數的類型為字符串。每次挪用va_arg後,參數列表ap都邑被更改,以使得下次挪用時能獲得下一個參數。
va_end(ap);用於對參數列表停止一些清算任務。挪用完va_end後,ap便不再有用。
以上法式給了我們一個完成printf函數的是思緒,即:經由過程挪用va_start函數,來獲得參數列表,然後我們一個個掏出參數來停止輸入便可。
3.實例
例如:關於printf(“a=%d,b=%s,c=%c”,a,b,c)語句;fmt的值為a=%d,b=%s,c=%c,挪用va_start函數將參數a,b,c存入了ap中。留意到:fmt中的%為特別字符,緊跟%後的參數指清楚明了參數類型.
是以我們的簡略單純printf函數以下:
#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);
}
從下面我們可以曉得可變參數函數的編寫,必需要傳入一個參數fmt,用來告知我們的函數如何去肯定參數的個數。我們的可變參數函數是經由過程本身解析這個參數來肯定函數參數個數的。
好比,我們編寫一個乞降函數,其函數完成以下:
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;
}
總結一下就是:經由過程va_start初始化參數列表(也就可以獲得詳細的參數個數了),然後應用va_arg函數從參數列表中掏出你想要的參數,最初挪用va_end履行清算任務。