- 1、本文档共8页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
CTricks26I386平台C函数的可变参数表VariableArguments
C++Tricks2.6I386
平台C函数的可变参
数表(Variable
Ar uments)
从导⼊
2.6I386平台C函数的可变
参数表(Variable
Ar uments)
基于前⽂(2.4节)分析,我们可以不通过函数签名,
直接通过指针运算,来得到函数的参数。由于参数的压
栈和弹出操作都由主调函数进⾏,所以被调函数对于参
数的真实数量不需要知晓。因此,函数签名中的变量声
明不是必需的。为了⽀持这种参数使⽤形式,C语⾔提供
可变参数表。可变参数表的语法形式是在参数表末尾添
加三个句点形成的省略号“...” :
void (inta,char*c,...);
省略号之前的逗号是可选的,并不影响词法语法分
析。上⾯的函数 可以接受2个或2个以上的参数,前两个
参数的类型固定,其后的参数类型未知,参数的个数也
未知。为了知道参数个数,我们必须通过其他⽅法,⽐
如通过第⼀个参数传递 :
(3,”Hello”,2,4,5);//调⽤ 并传递5个参数,其中后3
个为可变参数。
在函数的实现代码中,可以通过2.4节叙述的,参数
在栈中的排列顺序,来访问位于可变参数表的参数。⽐
如:
void (inta,char*c...){
void*pc=c;int*pi=static_castint*(pc)+1;//将
pi指向⾸个可变参数
for(inti=0;ia;i++)std::coutpi[i]”” ;
std::coutcstd::endl;
}
我们甚⾄可以让⼀个函数的所有参数都是可变参
数,只要有办法获知参数的数量即可。⽐如,我们约
定,在传递给addAll的参数都是int,并且最后⼀个以0
结束 :
intaddAll(...);
inta=f(1,4,2,5,7,0);
那么addAll可以这样实现 :
intaddAll(...){
intsum=0;int*p=sum;//p指向第⼀个局部变量
p+=3;//跳过sum,ebp,eip,现在p指向第⼀个参
数
for(;*p;++p)//如果p不指向0就继续循环
sum+=*p;
returnsum;
}
可变参数表的最⼴泛应⽤是C的标准库函数中的格式
化输⼊输出:printf和scanf。
voidprintf(char*c,...);
voidscanf(char*c,...);
两者都通过它的⾸个参数指出后续参数表中的参数
类型和参数数量。
如果可变参数表中的参数类型不⼀样,那么操纵可
变参数表就需要复杂的指针运算,并且还要时刻注意边
界对⻬(ali n)问题,⾮常令⼈头痛。好在C标准库提供了
⽤于操纵可变参数表的宏(macro)和结构(struct),他们
被定义在库⽂件stdar .h中:
typedefstruct{char*p;intoffset;}va_list;
#defineva_start(valist,ar )
#defineva_ar (valist,type)
#defineva_end(valist)
其中结构va_list⽤于指⽰参数在栈中的位置,宏
va_start接受⼀个va_list和函数的可变参数表之前的参
数,通过第⼀个参数初始化va_list中的相应数据,因此
要使⽤stdar .h中的宏,你的可变参数表的函数必须⾄
少有⼀个具名参数。va_ar 返回下⼀个类型为type的参
数,va_end结束可变参数表的使⽤。还是以上⽂的
addAll为例,这次写出它的使⽤标准宏的版本 :
intaddAll(inti,...)
{
va_listvl;//定义⼀个va_list结构
va_start(vl,i);//⽤省略号之前的参数初始化vl
if(i=0)return0;//如果第⼀个参数就是0,返回
intsum=i;//将第⼀个参数加⼊sum
for(;;){
i=va_ar (vl,int);/
文档评论(0)