C语言之可变参数问题
当前位置:以往代写 > C/C++ 教程 >C语言之可变参数问题
2019-06-13

C语言之可变参数问题

C语言之可变参数问题

副标题#e#

概述

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,则用来表白实际的参数个数,这为我们利用提供了进一步的利便,虽然,这个参数不是必须的。

固然参数没有牢靠形式,但我们一定要在函数中理会参数的意义,因此,理所虽然会有一个要求,就是挪用者和被调者之间要对参数区内容的名目,巨细,有效性等所有方面告竣一致,不然背道而驰各说各话就惨了。


#p#副标题#e#

问题:可变长参数的通报

有时候,需要编写一个函数,将它的可变长参数直接通报给别的的函数,请问,这个要求可否实现?

谜底与阐明:

今朝,你尚无步伐直接做到这一点,可是我们可以迂回前进,首先,我们界说被挪用函数的参数为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)))

这样就可以通过编译查抄了。

#p#副标题#e#

问题:可变长参数的获取

有这样一个具有可变长参数的函数,个中有下列代码用来获取范例为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()来确定所有实际挪用时可变长参数的范例和值。

    关键字:

在线提交作业