📄 faqcat744e.html
字号:
while((p = va_arg(argp, char *)) != NULL) /* includes first */ strcat(retbuf, p); va_end(argp); return retbuf;}</pre>(Notethat there is no semicolon after <TT>va_dcl</TT>.Note that in this case,no special treatment for the first argument is necessary.)You may also have todeclare the string functions by handrather than using <TT><string.h></TT>.</p><p>If you can manage to find a system with <TT>vfprintf</TT>but without <TT><stdarg.h></TT>,here is a version of the <TT>error</TT> function(from question <a href="faqcat744e.html?sec=varargs#vprintf">15.5</a>)using <TT><varargs.h></TT>:<pre>#include <stdio.h>#include <varargs.h>void error(va_alist)va_dcl /* no semicolon */ { char *fmt; va_list argp; fprintf(stderr, "error: "); va_start(argp); fmt = va_arg(argp, char *); vfprintf(stderr, fmt, argp); va_end(argp); fprintf(stderr, "\n");}</pre>(Notethatin contrast to <TT><stdarg.h></TT>,under <TT><varargs.h></TT> <em>all</em> arguments are variable,sothe <TT>fmt</TT> argument must also be picked up via <TT>va_arg</TT>.)</p><p>References:H&S Sec. 11.4 pp. 296-9<br>CT&P Sec. A.2 pp. 134-139<br>PCS Sec. 11 pp. 184-5, Sec. 13 p. 250<hr><hr><hr><a name="nargs"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../varargs/nargs.html"><!-- qtag -->Question 15.8</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>How can I discover how many arguments a function was actuallycalled with?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>This information is not available to a portable program.Some old systems provided a nonstandard <TT>nargs</TT>function,but its use was always questionable,since it typically returned the numberof words passed,not the number of arguments.(Structures,<TT>long int</TT>s,andfloating point valuesare usually passed asseveral words.)</p><p>Any function which takes a variable number of arguments must beable to determine<em>from the arguments themselves</em>how many of themthere are.<TT>printf</TT>-like functions do this by looking for formattingspecifiers (<TT>%d</TT> and the like) in the format string (which is whythese functions fail badly if the format string does not matchthe argument list).Another common technique,applicablewhen the arguments are all of the same type,is to use a sentinelvalue(often 0, -1, or an appropriately-cast null pointer)at the end of the list(see the<TT>execl</TT>and<TT>vstrcat</TT>examplesinquestions<a href="faqcat1f1a.html?sec=null#null2">5.2</a>and<a href="faqcat744e.html?sec=varargs#varargs1">15.4</a>).Finally,if thetypes are predictable,you can pass an explicit count of the number of variable arguments(although it's usually a nuisance for the caller to supply).</p><p>References:PCS Sec. 11 pp. 167-8<hr><hr><hr><a name="onefixedarg"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../varargs/onefixedarg.html"><!-- qtag -->Question 15.9</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>My compiler isn't letting me declare a function<pre> int f(...) { }</pre>i.e. accepting a variable number of arguments,butwith no fixed arguments at all.</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>Standard C requires at least one fixed argument,in part so that you can hand itto <TT>va_start</TT>.(In any case,you often need a fixed argumentto determine the number,and perhaps the types,of the variable arguments.)See also question <a href="faqcat744e.html?sec=varargs#float">15.10</a>.</p><p>References:ISO Sec. 6.5.4, Sec. 6.5.4.3, Sec. 7.8.1.1<br>H&S Sec. 9.2 p. 263<hr><hr><hr><a name="float"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../varargs/float.html"><!-- qtag -->Question 15.10</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>I have a varargs function which accepts a <TT>float</TT> parameter.Why isn't<pre>va_arg(argp, float)</pre>working?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>In the variable-length part of variable-length argument lists,theold``default argument promotions''apply:arguments of type <TT>float</TT> are always promoted(widened)to type <TT>double</TT>,and types <TT>char</TT> and <TT>short int</TT> are promoted to <TT>int</TT>.Therefore, it is never correct to invoke<TT>va_arg(argp, float)</TT>;insteadyou shouldalways use<TT>va_arg(argp, double)</TT>.Similarly, use<TT>va_arg(argp, int)</TT>to retrieve arguments which were originally<TT>char</TT>, <TT>short</TT>, or <TT>int</TT>.(For analogous reasons,the last ``fixed'' argument,as handed to <TT>va_start</TT>,should not be widenable,either.)See also questions <a href="faqcat7d4b.html?sec=ansi#argpromos">11.3</a>and <a href="faqcat744e.html?sec=varargs#promos">15.2</a>.</p><p>References:ISO Sec. 6.3.2.2<br>Rationale Sec. 4.8.1.2<br>H&S Sec. 11.4 p. 297<hr><hr><hr><a name="funcptr"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../varargs/funcptr.html"><!-- qtag -->Question 15.11</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>I can't get <TT>va_arg</TT> to pull in an argumentof type pointer-to-function.</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>Try using a <TT>typedef</TT> for the function pointer type.</p><p>The type-rewriting games whichthe <TT>va_arg</TT> macrotypicallyplays are stymiedby overly-complicated types such aspointer-to-function.To illustrate,a simplified implementation of <TT>va_arg</TT> is<pre> #define va_arg(argp, type) \ (*(type *)(((argp) += sizeof(type)) - sizeof(type)))</pre>where <TT>argp</TT>'stype(<TT>va_list</TT>)is <TT>char *</TT>.When you attempt to invoke<pre> va_arg(argp, int (*)())</pre>the expansion is<pre> (*(int (*)() *)(((argp) += sizeof(int (*)())) - sizeof(int (*)())))</pre>which is a syntax error(the first cast <TT>(int (*)() *)</TT> is meaningless).<a href="../../varargs/opaque.html" rel=subdocument>[footnote]</a></p><p>If youusea <TT>typedef</TT>for the function pointer type, however, all will be well.Given<pre> typedef int (*funcptr)();</pre>the expansion of<pre> va_arg(argp, funcptr)</pre>is<pre> (*(funcptr *)(((argp) += sizeof(funcptr)) - sizeof(funcptr)))</pre>which works correctly.</p><p>See alsoquestions <a href="faqcatd3c2.html?sec=decl#typedefvsdefine">1.13</a>, <a href="faqcatd3c2.html?sec=decl#pfitypedef">1.17</a>, and <a href="faqcatd3c2.html?sec=decl#cdecl1">1.21</a>.</p><p>References:ISO Sec. 7.8.1.2<br>Rationale Sec. 4.8.1.2<hr><hr><hr><a name="handoff"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../varargs/handoff.html"><!-- qtag -->Question 15.12</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>How can I write a function which takes a variable number ofarguments and passes them to some other function (which takes a variable number of arguments)?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>In general, you cannot.Ideally,you should provide a version of that other function which accepts a<TT>va_list</TT> pointer.</p><p>Suppose you want to write a <TT>faterror</TT> functionwhich will print a fatal error message, then exit.You might like to write it in terms of the <TT>error</TT> function of question <a href="faqcat744e.html?sec=varargs#vprintf">15.5</a>:<pre> void faterror(const char *fmt, ...) { error(fmt, <I>what goes here?</I> ); exit(EXIT_FAILURE); }</pre>but it's not obvious how to hand <TT>faterror</TT>'s arguments off to <TT>error</TT>.</p><p>Proceed as follows.First split up the existing <TT>error</TT> functionto create a new <TT>verror</TT>which accepts not a variable argument listbut a single <TT>va_list</TT> pointer.(Note that doing so is littleextra work,because <TT>verror</TT> contains much of the codethat used to be in <TT>error</TT>,and the new <TT>error</TT> becomes a simple wrapperaround <TT>verror</TT>.)<pre>#include <stdio.h>#include <stdarg.h>void verror(const char *fmt, va_list argp){ fprintf(stderr, "error: "); vfprintf(stderr, fmt, argp); fprintf(stderr, "\n");}void error(const char *fmt, ...){ va_list argp; va_start(argp, fmt); verror(fmt, argp); va_end(argp);}</pre></p><p>Now you can write <TT>faterror</TT>,and have it call <TT>verror</TT>, too:<pre>#include <stdlib.h>void faterror(const char *fmt, ...){ va_list argp; va_start(argp, fmt); verror(fmt, argp); va_end(argp); exit(EXIT_FAILURE);}</pre>Note that therelationbetween <TT>error</TT> and <TT>verror</TT>is exactly that which holds betweene.g. <TT>printf</TT> and <TT>vprintf</TT>.In fact,as Chris Torek has observed,whenever you find yourself writing a varargs function,it's a good idea to write two versions of it:one(like <TT>verror</TT>)whichaccepts a <TT>va_list</TT> and does the work,and one(like the revised <TT>error</TT>)which is a simple wrapper.The only real restriction on this techniqueis thata function like <TT>verror</TT>can scan the arguments just once;there is no way for it to reinvoke va_start.</p><p>If you do not have the optionof rewritingthe lower-level function(<TT>error</TT>, in this example)to accept a <TT>va_list</TT>,such that you find yourself needing to passthe variable arguments thatone function(e.g. <TT>faterror</TT>)receiveson to another as actual arguments,no portable solution is possible.(The problemcould perhapsbe solved by resorting to machine-specificassembly language;see alsoquestion <a href="faqcat744e.html?sec=varargs#invvarargs">15.13</a>.)</p><p>One approach that would <em>not</em> work would be something like<pre> void faterror(const char *fmt, ...) { va_list argp; va_start(argp, fmt); error(fmt, argp); /* WRONG */ va_end(argp); exit(EXIT_FAILURE); }</pre>A<TT>va_list</TT> is<em>not</em>itself a variable argument list;it's really sort of a pointer to one.That is, a function which accepts a <TT>va_list</TT> is not itself varargs,nor vice versa.</p><p>Another kludge that is sometimes used,and which sometimes works even though it is grossly nonportable,is to use a lot of <TT>int</TT> arguments,hoping that there are enough of them and that they can somehow pass through pointer, floating-point, and other arguments as well:<pre> void faterror(fmt, a1, a2, a3, a4, a5, a6) char *fmt; int a1, a2, a3, a4, a5, a6; { error(fmt, a1, a2, a3, a4, a5, a6); /* VERY WRONG */ exit(EXIT_FAILURE); }</pre>This example is presentedonly for the purpose of urging you <em>not</em> to use it;please don't try it just because you saw it here.<hr><hr><hr><a name="invvarargs"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../varargs/invvarargs.html"><!-- qtag -->Question 15.13</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>How can I call a function with an argument list built up at run time?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>There is no guaranteed or portable way to do this.If you're curious,this list's editorhas a few<a href="../../varargs/wacky.html" rel=subdocument>wacky ideas</a>you could try...</p><p>Instead of an actual argument list,you might considerpassing an array of generic(<TT>void *</TT>)pointers.The called function can then step through the array,much like <TT>main()</TT> might step through <TT>argv</TT>.(Obviously this works onlyif you have control over all the called functions.)</p><p>(See also question<a href="faqcatea63.html?sec=osdep#dynlink">19.36</a>.)</p><p>Additional links:<a href="../../varargs/wacky.html" rel=subdocument>“wacky ideas”</a><hr><hr><hr><hr><p>Read sequentially:<a href="faqcat973e.html?sec=fp" rev=precedes>prev</a><a href="faqcat5e04.html?sec=strangeprob" rel=precedes>next</a><a href="faqcat.html" rev=subdocument>up</a></p><hr><p><br><!-- lastfooter --><a href="../../about.html">about this FAQ list</a> <a href="../../eskimo.html">about eskimo</a> <a href="../../search.html">search</a> <a href="../../feedback.html">feedback</a> <a href="../../varargs/copyright.html">copyright</a><p>Hosted by<a href="http://www.eskimo.com/"><img src="../../../www.eskimo.com/img/link/eskitiny.gif" alt="Eskimo North"></a></body><!-- Mirrored from c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=varargs by HTTrack Website Copier/3.x [XR&CO'2008], Sat, 14 Mar 2009 07:58:21 GMT --></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -