* remove "\r" nonsense
[mascara-docs.git] / C / the.ansi.c.programming.language / c.programming.notes.int / sx11c.html
blob144056887eab64b56c89bcc342850c3afa5b1474
1 <!DOCTYPE HTML PUBLIC "-//W3O//DTD W3 HTML 2.0//EN">
2 <!-- This collection of hypertext pages is Copyright 1995-7 by Steve Summit. -->
3 <!-- This material may be freely redistributed and used -->
4 <!-- but may not be republished or sold without permission. -->
5 <html>
6 <head>
7 <link rev="owner" href="mailto:scs@eskimo.com">
8 <link rev="made" href="mailto:scs@eskimo.com">
9 <title>25.3 Special Issues with Varargs Functions</title>
10 <link href="sx11b.html" rev=precedes>
11 <link href="sx11.html" rev=subdocument>
12 </head>
13 <body>
14 <H2>25.3 Special Issues with Varargs Functions</H2>
16 <p>When a function with a variable-length argument list is called,
17 the variable arguments are passed
18 using C's old ``default argument promotions.''
19 These say that types <TT>char</TT> and <TT>short int</TT>
20 are automatically promoted to <TT>int</TT>,
21 and type <TT>float</TT> is automatically promoted to <TT>double</TT>.
22 Therefore, varargs functions will <em>never</em> receive
23 arguments of type <TT>char</TT>, <TT>short int</TT>, or <TT>float</TT>.
24 Furthermore, it's an error to ``pass'' the type names
25 <TT>char</TT>, <TT>short int</TT>, or <TT>float</TT>
26 as the second argument to the <TT>va_arg()</TT> macro.
27 Finally, for vaguely related reasons,
28 the last fixed argument
29 (the one whose name is passed as
30 the second argument to the <TT>va_start()</TT> macro)
31 should not be of type <TT>char</TT>, <TT>short int</TT>,
32 or <TT>float</TT>,
33 either.
34 </p><p>A frequently-asked question is,
35 ``How can I determine how many arguments
36 my function was actually called with?''
37 The answer,
38 as discussed above,
39 is that <em>you</em> (or your code) must figure it out somehow,
40 generally by looking at the arguments themselves
41 (or, in the case of <TT>printf</TT>,
42 by using clues which are designed into the first, fixed arguments).
43 There is no Standard way of asking
44 the compiler or run-time system
45 how many arguments were actually passed,
46 or what their types are.
47 </p><p>The macros <TT>va_start()</TT> and <TT>va_arg()</TT>
48 are referred to as macros because they can't possibly be functions.
49 <TT>va_start()</TT> initializes
50 (that is, sets the value of)
51 its first argument,
52 and it
53 uses its second argument not as a value but as a location.
55 Even more unusually,
56 <TT>va_arg()</TT> accepts a type name as its second argument,
57 which no function in C,
58 indeed no <em>anything</em> in C other than <TT>sizeof</TT>,
59 can ever do.
60 Finally,
61 <TT>va_arg()</TT> has no one return type
62 (as it would have to if it were a function);
63 the type it ``returns'' is determined by its second argument.
64 </p><p>The <TT>va_list</TT> type, whatever it is, is a mostly normal type.
65 In particular, you can pass it on to other functions,
66 and it is frequently quite useful to do so.
67 For example, suppose that you want to write an <TT>error</TT> function,
68 which will print nicely annotated error messages
69 complete with filenames, line numbers, severity indicators, and the like.
70 Furthermore, suppose that the rest of your program will find it useful,
71 when calling this <TT>error</TT> function,
72 to embed <TT>%</TT> sequences in the string to be printed,
73 requesting that extra arguments be interpolated,
74 just like <TT>printf</TT>.
75 The obvious question is,
76 will the <TT>error</TT> function have to duplicate
77 all of <TT>printf</TT>'s code
78 for parsing format strings and formatting variable arguments
79 (which isn't impossible, as we've seen),
80 or can it somehow call on <TT>printf</TT> or a related function
81 to do most of the work?
82 </p><p>To be precise, here's the outline of the <TT>error</TT> function
83 we'd like to write:
84 <pre>
85 extern char *filename; /* current input file name */
86 extern int lineno; /* current line number */
88 void error(char *msg, ...)
90 fprintf(stderr, "%s, line %d: error:", filename, lineno);
91 fprintf(stderr, msg, <I>what goes here?</I> );
92 fprintf(stderr, "\n");
94 </pre>
95 The tricky line is the second call to <TT>fprintf</TT>.
96 We have the string, <TT>msg</TT>,
97 we want
99 to print,
100 possibly containing <TT>%</TT> characters.
101 How do we pass down to <TT>fprintf</TT>
102 the extra arguments which our caller passed to us?
103 </p><p>The answer is that we don't;
104 there's no way to say
105 ``call this function with the same arguments I got,
106 however many of them there are.''
107 (The run-time system simply doesn't have enough information
108 to do this sort of thing,
109 which is why it can't tell you
110 how many arguments you got called with, either.)
111 However, there's a variant version of <TT>fprintf</TT>
112 which is designed
113 for just this sort of situation.
114 The variant is called <TT>vfprintf</TT>
115 (where
116 the <TT>v</TT>
117 stands for ``varargs''),
118 and a call to it looks something like this:
119 <pre>
120 void error(char *msg, ...)
122 va_list argp;
124 fprintf(stderr, "%s, line %d: error:", filename, lineno);
125 va_start(argp, msg);
126 vfprintf(stderr, msg, argp);
127 va_end(argp);
128 fprintf(stderr, "\n");
130 </pre>
131 We declare a local variable of type <TT>va_list</TT>
132 and call <TT>va_start()</TT>,
133 as before.
134 However, all we do with our <TT>argp</TT> variable
135 is pass it to <TT>vfprintf</TT> as its third argument.
136 <TT>vfprintf</TT> then does all the work--if
137 we could look inside it,
138 it would look a lot like our version of <TT>printf</TT> above,
139 except that <TT>vfprintf</TT> does <em>not</em> call
140 <TT>va_start()</TT>,
141 because its caller already has.
142 Notice that <TT>vfprintf</TT> does <em>not</em> accept
143 a variable number of arguments;
144 it accepts exactly three arguments,
145 the third of which is essentially a ``pointer''
146 to the extra arguments it will need.
147 </p><p>There are also ``varargs'' versions of
148 <TT>printf</TT> and <TT>sprintf</TT>,
149 namely <TT>vprintf</TT> and <TT>vsprintf</TT>.
150 These follow the same pattern,
151 accepting a single last argument of type <TT>va_list</TT>
152 in lieu of an actual variable-length argument list.
153 </p><p>(Notice that the <TT>error</TT> function above
154 also called <TT>va_end()</TT>.
155 This makes sense,
156 since <TT>error</TT> was the one who called <TT>va_start()</TT>.
157 The above pattern works,
158 but more complicated ones may not.
159 For example,
160 it's not guaranteed that you can
161 pick a few arguments off of a <TT>va_list</TT>,
162 pass the <TT>va_list</TT> to a subfunction to pick a few more off,
163 and then pick the last ones off yourself.
164 Also, there's no direct way to ``rewind'' a <TT>va_list</TT>,
165 although it's permissible to call <TT>va_end()</TT>
166 and then <TT>va_start()</TT> again,
167 to start over again.)
168 </p><hr>
170 Read sequentially:
171 <a href="sx11b.html" rev=precedes>prev</a>
172 <a href="sx11.html" rev=subdocument>up</a>
173 <a href="top.html">top</a>
174 </p>
176 This page by <a href="http://www.eskimo.com/~scs/">Steve Summit</a>
177 // <a href="copyright.html">Copyright</a> 1996-1999
178 // <a href="mailto:scs@eskimo.com">mail feedback</a>
179 </p>
180 </body>
181 </html>