中易网

C++ 多个函数参数问题

答案:3  悬赏:20  
解决时间 2021-01-25 11:35
C++ 多个函数参数问题
最佳答案
可变参数即表示参数个数可以变化,可多可少,也表示参数的类型也可以变化,可以是int,double还可以是char*,类,结构体等等。可变参数是实现printf(),sprintf()等函数的关键之处,也可以用可变参数来对任意数量的数据进行求和,求平均值带来方便(不然就用数组或每种写个重载)。在C#中有专门的关键字parame,但在C,C++并没有类似的语法,不过幸好提供这方面的处理函数,本文将重点介绍如何使用这些函数。

第一步 可变参数表示
用三个点…来表示,查看printf()函数和scanf()函数的声明:
int printf(const char *, ...);
int scanf(const char *, ...);
这三个点用在宏中就是变参宏(Variadic Macros),默认名称为__VA_ARGS__。如:
#define WriteLine(...) { printf(__VA_ARGS__); putchar('\n');}
再WriteLine("MoreWindows");
考虑下printf()的返回值是表示输出的字节数。将上面宏改成:
#define WriteLine (...) printf(__VA_ARGS__) + (putchar('\n') != EOF ? 1: 0);
这样就可以得到WriteLine宏的返回值了,它将返回输出的字节数,包括最后的’\n’。如下例所示i和j都将输出12。
int i = WriteLine("MoreWindows");
WriteLine("%d", i);
int j = printf("%s\n", "MoreWindows");
WriteLine("%d", j);

第二步 如何处理va_list类型
函数内部对可变参数都用va_list及与它相关的三个宏来处理,这是实现变参参数的关键之处。
中可以找到va_list的定义:
typedef char *va_list;
再介绍与它关系密切的三个宏要介绍下:va_start(),va_end()和va_arg()。
同样在中可以找到这三个宏的定义:
#define va_start(ap,v)( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_end(ap)( ap = (va_list)0 )
#define va_arg(ap,t)( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
其中用到的_INTSIZEOF宏定义如下:
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
来分析这四个宏:
va_end(ap)这个最简单,就是将指针置成NULL。
va_start(ap,v)中ap = (va_list)&v + _INTSIZEOF(v)先是取v的地址,再加上_INTSIZEOF(v)。_INTSIZEOF(v)就有点小复杂了。( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )全是位操作,看起来有点麻烦,其实不然,非常简单的,就是取整到sizeof(int)。比如sizeof(int)为4,1,2,3,4就取4,5,6,7,8就取8。对x向n取整用C语言的算术表达就是((x+n-1)/n)*n,当n为2的幂时可以将最后二步运算换成位操作——将最低 n - 1个二进制位清 0就可以了。
va_arg(ap,t)就是从ap中取出类型为t的数据,并将指针相应后移。如va_arg(ap, int)就表示取出一个int数据并将指针向移四个字节。
因此在函数中先用va_start()得到变参的起始地址,再用va_arg()一个一个取值,最后再用va_end()收尾就可以解析可变参数了。

第三步 vfprintf()函数和vsprintf()函数
vfprintf()这个函数很重要,光从名字上看就知道它与经常使用的printf()函数有很大的关联。它有多个重载版本,这里讲解最常用的一种:
函数原型
int vfprintf(
FILE *stream,
const char *format,
va_list argptr
);
第一个参数为一个FILE指针。FILE结构在C语言的读写文件必不可少。要对屏幕输出传入stdout。
第二个参数指定输出的格式。
第三个参数是va_list类型,这个少见,但其实就是一个char*表示可变参参数的起始地址。
返回值:成功返回输出的字节数(不包括最后的’\0’),失败返回-1。
vsprintf()与上面函数类似,就只列出函数原型了:
int vsprintf(
char *buffer,
const char *format,
va_list argptr
);
还有一个int _vscprintf(const char *format, va_list argptr );可以用来计算vsprintf()函数中的buffer字符串要多少字节的空间。

代码范例
下面就给出了自己实现的printf()函数(注1)与WriteLine()函数
int Printf(char *pszFormat, ...)
{
va_list pArgList;

va_start(pArgList, pszFormat);
int nByteWrite = vfprintf(stdout, pszFormat, pArgList);
va_end(pArgList);

return nByteWrite;
}

int WriteLine(char *pszFormat, ...)
{
va_list pArgList;

va_start(pArgList, pszFormat);
int nByteWrite = vfprintf(stdout, pszFormat, pArgList);
if (nByteWrite != -1)
putchar('\n'); //注2
va_end(pArgList);

return (nByteWrite == -1 ? -1 : nByteWrite + 1);
}
调用与printf()函数相同。
再给出一个用可变参数来求和,遗憾的在C,C++中无法确定传入的可变参数的个数(printf()中是通过扫描'%'个数来确实参数的个数的),因此要么就要指定个数,要么在参数的最后要设置哨兵数值:
设置哨兵数值:
const int GUARDNUMBER = 0; //哨兵标识
//变参参数的个数无法确定,在printf()中是通过扫描'%'个数,在这通过设置哨兵标识来确定变参参数的终止
int MySum(int i, ...)
{
int sum = i;
va_list argptr;

va_start(argptr, i);
while ((i = va_arg(argptr, int)) != GUARDNUMBER)
sum += i;
va_end(argptr);

return sum;
}
可以这样的调用: printf("%d\n", MySum(1, 3, 5, 7, 9, 0));
但不可以直接传入一个0: printf("%d\n", MySum(0)); //error
指定个数:
int MySum(int nCount, ...)
{
if (nCount <= 0)
return 0;

int sum = 0;
va_list argptr;

va_start(argptr, nCount);
for (int i = 0; i < nCount; i++)
sum += va_arg(argptr, int);
va_end(argptr);

return sum;
}
调用时第一个参数表示后面参数的个数如:
printf("%d\n", MySum(5, 1, 3, 5, 7, 9));
printf("%d\n", MySum(0));
代码所用的头文件:
#include
#include

可变参数的使用方法远远不止上述几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃。
全部回答
我暂时保留我的看法!
#包括
使用命名空间std;
结构jiegou
双升;
双角;
};
双calcu (双一,双B,双升,双角,结构jiegou&S)
{
双L1 = 0.5,
双角1 = 0.8;
/ /由于参数是一个参考,因此相当于进行了的jiegou成员下列成员。
SL = L1;
S.angle = ANGLE1;
返回0;
}
国际主要()
{
jiegou A;
/ / LZ不知道你的程序的目的,我在这里取前三个参数0,最后一个参数是一个对象,
calcu(0,0,0,0的结构, A)
/ /测试:输出0.5;
法院<<铝<< ENDL;
返回0;
}
我要举报
如以上问答内容为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
包干费
与和字有关的成语 与民俗
生理性高度近视如何降低度数
中国邮政储蓄银行24小时自助银行(莲花支行)(
厕所蹲便器没有存水弯 老有异味
怎样能够快速缓解皮肤晒伤?
激光点痣后能抽烟吗? 多久能恢复正常饮食?痂
高脂肪高尿酸高胆固醇吃OMEGA-3
山东到吉林顺丰多久能到
安全监理实施细则的基坑施工
乳晕刺青漂红脱跏后乳晕粉红乳头还是黑色怎么
帮会接引人在什么地方?找不到
贵州省罗旬嫌县云干乡离安顺普定多远
东莞石龙镇京瓷科技到清溪镇车站搭几路车
如何才能不让头发分叉
推荐资讯
一热敏电阻在0度和100度时,电阻值分别为200千
求有拉肚子镜头得动漫!!!
许俊宰什么时候发现女主是美人鱼
石英钟怎么使用钟表油
南京万达茂总经理坠楼身亡的经过如何?
成语 昼什么不什么的成语
2700除25怎么简便计算
瘦脸果是什么 副作用大吗
PCB板上的排阻与二极管怎么直接连用,谢谢了
贵阳火车站到沿河县最近的火车站是那个
挥毫自如.人们从他书写的一副对联中找到了刘
圣方汽车快速养护中心地址在哪,我要去那里办
手机登qq时,显示手机磁盘不足,清理后重新登
刺客的套装怎么选啊?