Newsgroups: comp.std.c Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!caen!hellgate.utah.edu!dog.ee.lbl.gov!elf.ee.lbl.gov!torek From: torek@elf.ee.lbl.gov (Chris Torek) Subject: Re: Is va_list defined by ? Organization: Lawrence Berkeley Laboratory, Berkeley References: <16863@hoptoad.uucp> Message-ID: <11852@dog.ee.lbl.gov> X-Local-Date: Fri, 5 Apr 91 16:29:28 PST Reply-To: torek@elf.ee.lbl.gov (Chris Torek) Date: Sat, 6 Apr 91 00:29:28 GMT In article <16863@hoptoad.uucp> gnu@hoptoad.uucp (John Gilmore) writes: >In an ANSI C implementation, it appears that the type "va_list" must be >defined by ... 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 , declare v*printf with something like: int vprintf(const char *fmt, struct __va_list *); C. in , define the type `va_list' with something like typedef struct __va_list *va_list; This introduces two new problems: is now machine dependent (an otherwise-unnecessary situation), and and 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 , which is a minor misnomer) that reads more or less as follows: /* faux MIPS */ #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 , , , and ), 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 just uses the sequence #include 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 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 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@ee.lbl.gov