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. -->
7 <link rev=
"owner" href=
"mailto:scs@eskimo.com">
8 <link rev=
"made" href=
"mailto:scs@eskimo.com">
9 <title>25.2 Writing a ``varargs'' Function
</title>
10 <link href=
"sx11a.html" rev=precedes
>
11 <link href=
"sx11c.html" rel=precedes
>
12 <link href=
"sx11.html" rev=subdocument
>
15 <H2>25.2 Writing a ``varargs'' Function
</H2>
17 <p>In ANSI C, the head of a varargs function looks just like its prototype.
18 We will illustrate by writing our own,
19 stripped-down version of
<TT>printf
</TT>.
20 The bare outline of the function definition will look like this:
22 void myprintf(const char *fmt, ...)
26 <TT>printf
</TT>'s job, of course,
29 to print its format string
31 looking for
<TT>%
</TT> characters and treating them specially.
32 So the main loop of
<TT>printf
</TT> will look like this:
34 #include
<stdio.h
>
36 void myprintf(const char *fmt, ...)
40 for(p = fmt; *p != '\
0'; p++)
45 <I>handle it specially
</I>
50 In this stripped-down version,
51 we won't worry about width and precision specifiers and other modifiers;
52 we'll always look at the very next character after the
<TT>%
</TT>
53 and assume that it's the primary format character.
54 Continuing to flesh out our outline, we get this:
56 #include
<stdio.h
>
58 void myprintf(const char *fmt, ...)
62 for(p = fmt; *p != '\
0'; p++)
73 <I>fetch and print a character
</I>
77 <I>fetch and print an integer
</I>
81 <I>fetch and print a string
</I>
85 <I>print an integer, in hexadecimal
</I>
89 <I>print a single %
</I>
95 (For clarity, we've rearranged
96 the former
<TT>if
</TT>/
<TT>else
</TT> statement slightly.
97 If the character we're looking at is not
<TT>%
</TT>,
98 we print it out and continue immediately
99 with the next iteration of the
<TT>for
</TT> loop.
100 This is a good example of the use of the
<TT>continue
</TT> statement.
101 Everything else in the body of the loop then
102 takes care of the case where we
<em>are
</em> looking at a
<TT>%
</TT>.)
103 </p><p>Printing these various argument types out will be relatively straightforward.
104 The $
64,
000 question, of course, is how to fetch the actual arguments.
105 The answer involves some specialized macros defined for us
106 by the standard header
<TT><stdarg.h
></TT>.
107 The macros we will use are
113 <TT>va_list
</TT> is a special ``pointer'' type
114 which allows us to manipulate a variable-length argument list.
115 <TT>va_start()
</TT> begins the processing of an argument list,
116 <TT>va_arg()
</TT> fetches arguments from it, and
117 <TT>va_end()
</TT> finishes processing.
118 (Therefore,
<TT>va_list
</TT> is a little bit like
119 the stdio
<TT>FILE *
</TT> type,
120 and
<TT>va_start
</TT> is a bit like
<TT>fopen
</TT>.)
121 </p><p>Here is the final version of our
<TT>myprintf
</TT> function,
122 illustrating the fetching, formatting, and printing
123 of the various argument types.
124 (For simplicity--of presentation, if nothing else--the
125 formatting step is deferred to
127 the nonstandard but popular
<TT>itoa
</TT> function.)
130 #include
<stdio.h
>
131 #include
<stdarg.h
>
133 extern char *itoa(int, char *, int);
135 void myprintf(const char *fmt, ...)
145 for(p = fmt; *p != '\
0'; p++)
156 i = va_arg(argp, int);
161 i = va_arg(argp, int);
162 s = itoa(i, fmtbuf,
10);
167 s = va_arg(argp, char *);
172 i = va_arg(argp, int);
173 s = itoa(i, fmtbuf,
16);
186 </p><p>Looking at the new lines, we have:
188 #include
<stdarg.h
>
190 This header file is required in any file
191 which uses the variable argument list (
<TT>va_
</TT>) macros.
195 This line declares a variable,
<TT>argp
</TT>,
196 which we use while manipulating the variable-length argument list.
197 The type of the variable is
<TT>va_list
</TT>,
198 a special type defined for us by
<TT><stdarg.h
></TT>.
202 This line initializes
<TT>argp
</TT>
203 and initiates the processing of the argument list.
204 The second argument to
<TT>va_start()
</TT> is simply
208 <TT>va_start()
</TT> uses this
211 where the variable arguments begin.
213 i = va_arg(argp, int);
215 And here's the heart of the matter.
216 <TT>va_arg()
</TT> fetches the next argument from the argument list.
217 The second argument to
<TT>va_arg()
</TT> is
218 the
<em>type
</em> of the argument we expect.
219 Notice carefully that
<em>we
</em> must supply this argument,
220 which implies that
<em>we
</em> must somehow know
221 what type of argument to expect next.
222 The variable-length argument list machinery does
<em>not
</em> know.
223 In this case, we know what the type of the next argument
227 the format character we're processing.
230 why such havoc results
231 when
<TT>printf
</TT>'s arguments
232 do not match its format string:
233 <TT>printf
</TT> tells the
<TT>va_arg
</TT> machinery
234 to grab an argument of one type,
235 with the type determined by one of the format specifiers,
236 but since the
<TT>va_arg
</TT> machinery doesn't know
237 what the actual argument type is,
238 there's no way for it to do any automatic conversion.
239 If the actual argument
240 has the right type for the
<TT>va_arg
</TT> call which grabs it
245 otherwise it doesn't.
246 </p><p>(You may have noticed that we fetched the character
247 to print for
<TT>%c
</TT>
248 as an
<TT>int
</TT>, not a
<TT>char
</TT>.
249 That's deliberate, and is explained in the next section.)
251 s = va_arg(argp, char *);
253 Here's another invocation of
<TT>va_arg()
</TT>,
254 this time fetching a string, represented as a character pointer,
259 Finally, when we're all finished processing the argument list,
260 we call
<TT>va_end()
</TT>, which performs any necessary cleanup.
264 <a href=
"sx11a.html" rev=precedes
>prev
</a>
265 <a href=
"sx11c.html" rel=precedes
>next
</a>
266 <a href=
"sx11.html" rev=subdocument
>up
</a>
267 <a href=
"top.html">top
</a>
270 This page by
<a href=
"http://www.eskimo.com/~scs/">Steve Summit
</a>
271 //
<a href=
"copyright.html">Copyright
</a> 1996-
1999
272 //
<a href=
"mailto:scs@eskimo.com">mail feedback
</a>