Is va_list defined by <stdio.h>?
Chris Torek
torek at elf.ee.lbl.gov
Sat Apr 6 10:29:28 AEST 1991
In article <16863 at hoptoad.uucp> gnu at hoptoad.uucp (John Gilmore) writes:
>In an ANSI C implementation, it appears that the type "va_list" must be
>defined by <stdio.h> ...
No; in fact, the type `va_list' must not be defined there, but must be
*used* there regardless (as you note).
This leaves the problem of somehow using a type without first defining
it. There is a way, based on the observation that `typedef' does not
define a new type, but rather defines a new name for an existing type.
What one does, then, is this:
A. Define some underlying representation V for `va_list'. This is
machine dependent, but is typically something like `pointer to
char' or `pointer to struct __va_list'.
B. In <stdio.h>, declare v*printf with something like:
int vprintf(const char *fmt, struct __va_list *);
C. in <stdarg.h>, define the type `va_list' with something like
typedef struct __va_list *va_list;
This introduces two new problems: <stdio.h> is now machine dependent
(an otherwise-unnecessary situation), and <stdarg.h> and <stdio.h> must
somehow be kept in sync.
What we have done in the current BSD system, which solves all of this,
is create a machine-dependent header file (found in <machine/ansi.h>,
which is a minor misnomer) that reads more or less as follows:
/* faux MIPS <machine/ansi.h> */
#ifndef _ANSI_H_
#define _ANSI_H_
struct __va_list { int n0; char *p0, *p1; }; /* 2 save areas */
#define _CLOCK_T_ unsigned long
#define _PTRDIFF_T_ int
#define _SIZE_T_ unsigned int
#define _TIME_T_ unsigned int
#define _VA_LIST_ struct __va_list *
#define _WCHAR_T_ unsigned short
#endif /* _ANSI_H_ */
This file is included whenever any of the machine-dependent types is
required. Typedefs that appear in more than one standard header,
such as size_t (which appears in <stddef.h>, <stdio.h>, <string.h>,
and <time.h>), are defined in each standard header with the sequence
#ifdef _SIZE_T_
typedef _SIZE_T_ size_t;
#undef _SIZE_T_
#endif
so that each such typedef appears at most once. Typedefs that appear in
only one header (namely va_list) are simply defined via
typedef _VA_LIST_ va_list;
and <stdio.h> just uses the sequence
#include <machine/ansi.h>
int vprintf(const char *, _VA_LIST_);
(had va_list to appear in more than one standard header, we would have
had to create two implementation-space macro names for it; fortunately
this is not the case).
This `backwards' sequence (of defining the types via macros, then
turning those into typedefs exactly once by undefining the macro in the
process) uses the minimal amount of verbiage. Another scheme is to
have one macro for each type, and another for each `typedef has been
done' flag, but this is unnecessary.
Machine-dependent headers such as <stdarg.h> are in fact read from
the `machine' directory as well.
Note that the technique used in SunOS 4.1 and 4.1.1, in which
<sys/stdtypes.h> contains all the `typedef's for all standard headers,
is incorrect, precisely because of the problem addressed here (some
headers must use some types which those same headers must not define).
(Good grief, these one-sentence paragraphs are starting to look like
Bill-Joy-ese. :-) I find all the passive voice annoying too. [Look
what happens when you get wheedled into editing man pages....])
--
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA Domain: torek at ee.lbl.gov
More information about the Comp.std.c
mailing list