常见的有catch(...)和 int printf(const char*,...);前者容易理解,省略号代表其他所有情况,后者吗..?
其实本质上应该都是 不定参数函数.它的调用方式是_cedel,也就是说由被调用都恢复堆栈。原理如下:
template <class FT,class MT=FT>
class arg_list{
public:
arg_list(FT &ft):_ft(&ft),_count(0){va_start(_val,*_ft);}
MT next(){_count++;return va_arg(_val,MT);}
void end(){va_end(_val);}
int count(){return _count;}
private:
FT* _ft;
va_list _val;
int _count;
};
int average(int p,...){
int sum=0,int i=p,count=0;
arg_list<int> arg(p);
while(i!=END_ARG)
sum+=i,i=arg.next();
arg.end();
return sum/arg.count();
}
应用实例:
void Msg(TCHAR *szFormat, ...);
void Msg(TCHAR *szFormat, ...)
{
TCHAR szBuffer[1024]; // Large buffer for long filenames or URLs
const size_t NUMCHARS = sizeof(szBuffer) / sizeof(szBuffer[0]);
const int LASTCHAR = NUMCHARS - 1;
// Format the input string
va_list pArgs;
va_start(pArgs, szFormat);
// Use a bounded buffer size to prevent buffer overruns. Limit count to
// character size minus one to allow for a NULL terminating character.
_vsntprintf(szBuffer, NUMCHARS - 1, szFormat, pArgs);
va_end(pArgs);
// Ensure that the formatted string is NULL-terminated
szBuffer[LASTCHAR] = TEXT('/0');
MessageBox(NULL, szBuffer, TEXT("PlayCap Message"), MB_OK | MB_ICONERROR);
}
引申(摘自http://seraph-zhang.spaces.live.com/blog/cns!9f6aca94097e3f05!1220.entry):
__cdecl是C/C++语言所采用缺省调用规范,__stdcall是WINAPI采用的缺省调用规范,其区别在于__cdecl是由调用函数一方负责维护函数参数堆栈而__stdcall是由被调用一方维护函数参数堆栈,从assembly代码的角度考虑__cdecl调用规范最后返回时的RET指令并没有参数而__stdcall规范返回时RET指令必然带有指示函数返回时需要从堆栈中弹出多少个函数参变量这样一个参数,因为__stdcall由被调用一方负责维护堆栈那么也只有在RET之前退栈而不是RET之后,同时__cdecl和__stdcall在函数参数压栈的时候都是采用由右至左的顺序的。这样就引出几个特殊的问题,例如在C/C++中对于Main函数只能采用__cdecl这种调用规约;__cedel可用于参数个数发生变化的函数而__stdcall只能用于函数参数个数不变的情况等等。