C语言中有一种长度不鲜明的参数,形如:”…”,它根本用在参数个数不分明的函数中,大家最轻易想到的例证是printf函数。

  原型:

int printf( const char *format [, argument]… );

  使用例:

printf("Enjoy yourself everyday!n");
printf("The value is %d!n", value);

  这种可变参数能够说是C语言二个相比难驾驭的有个别,这里会由多少个难题抓住部分对它的深入分析。

  注意:在C++中有函数重载(overload)能够用来区分区别函数参数的调用,但它如故不能够代表狂妄数量的函数参数。

  问题:printf的实现

  请问,怎样团结完毕printf函数,如什么地方理当中的可变参数难点?
答案与分析:

  在行业内部C语言中定义了三个头文件<stdarg.h>特意用来应付可变参数列表,它包涵了一组宏,和两个va_list的typedef评释。八个第一名达成如下:

typedef char* va_list;
#define va_start(list) list = (char*)&va_alist
#define va_end(list)
#define va_arg(list, mode)
((mode*) (list += sizeof(mode)))[-1]
自己实现printf:
#include <stdarg.h>
int printf(char* format, …)
{
va_list ap;
va_start(ap, format);
int n = vprintf(format, ap);
va_end(ap);
return n;
}

  难题:运转时才明确的参数

  有未有主意写二个函数,那一个函数参数的绘声绘色格局得以在运作时才鲜明?

  答案与深入分析:

  近期未有”正规”的解决办法,可是独门偏方倒是有三个,因为有一个函数已经给我们做出了那方面包车型地铁样子,那就是main(卡塔尔,它的原型是:

int main(int argc,char *argv[]);

  函数的参数是argc和argv。

  浓郁想转手,”只能在运转时规定参数情势”,也正是说你不能从表明中观望所接收的参数,也正是参数根本就不曾永世的款式。常用的章程是你能够通过定义二个void
*类型的参数,用它来指向实际的参数区,然后在函数中依照依据要求自由解释它们的意思。那正是main函数中argv的含义,而argc,则用来申明实际的参数个数,那为大家使用提供了更为的有益,当然,那么些参数不是少不了的。

  就算参数未有永世格局,但大家必定会就要在函数中剖析参数的意义,因而,理所必然会有三个渴求,就是调用者和被调者之间要对参数区内容的格式,大小,有效性等全体地点达成一致,不然掘地寻天各说各话就惨了。

  难点:可变长参数的传递

  有的时候候,需求编写制定贰个函数,将它的可变长参数直接传送给别的的函数,请问,这几个必要是还是不是实现?

  答案与解析:

  近日,你尚无办法直接完事这一点,不过大家得以迂回前进,首先,大家定义被调用函数的参数为va_list类型,同有时候在调用函数中将可变长参数列表转换为va_list,那样就可以张开变长参数的传递了。看如下所示:

void subfunc (char *fmt, va_list argp)
{

arg = va_arg (fmt, argp); /* 从argp中逐一取出所要的参数 */

}

void mainfunc (char *fmt, …)
{
va_list argp;
va_start (argp, fmt); /* 将可变长参数转换为va_list */
subfunc (fmt, argp); /* 将va_list传递给子函数 */
va_end (argp);

}

  难点:可变长参数中项目为函数指针

  我想使用va_arg来提收取可变长参数中项目为函数指针的参数,结果却接连不得法,为什么?

  答案与解析:

  这个与va_arg的兑现存关。二个粗略的、演示版的va_arg完成如下:

#define va_arg(argp, type)
(*(type *)(((argp) += sizeof(type)) – sizeof(type)))

  此中,argp的品类是char *。

  即便你想用va_arg从可变参数列表中提收取函数指针类型的参数,比如

int (*)(),则va_arg(argp, int (*)())被扩展为:
(*(int (*)() *)(((argp) += sizeof (int (*)())) -sizeof (int (*)())))

  显然,(int (*)() *)是虚幻的。

  解决那一个主题素材的诀纵然将函数指针用typedef定义成叁个单独的数据类型,比如:

typedef int (*funcptr)();

  当时再调用va_arg(argp, funcptr卡塔尔将被增添为:

(* (funcptr *)(((argp) += sizeof (funcptr)) – sizeof (funcptr)))

  那样就足以经过编写翻译检查了。

  难点:可变长参数的获得

  有这样四个持有可变长参数的函数,此中有下列代码用来收获项目为float的实参:

va_arg (argp, float);

  那样做能够啊?

  答案与分析:

  不得以。在可变长参数中,应用的是”加宽”原则。也正是float类型被扩展成double;char,
short被扩充成int。由此,假诺你要去可变长参数列表中原本为float类型的参数,需求用va_arg(argp,
double卡塔尔。对char和short类型的则用va_arg(argp, int)。

  难点:定义可变长参数的三个限定

  为啥小编的编写翻译器不许小编定义如下的函数,也正是可变长参数,可是从未其余的长久参数?

int f (…)
{

}

  答案与剖析:

  不能。那是ANSI C 所要求的,你足足得定义三个定点参数。

  这一个参数将被传送给va_start(),然后用va_arg()和va_end(卡塔尔(قطر‎来分明全数实际调用时可变长参数的类型和值。

相关文章