va_list used in <stdio.h>

Steve Summit scs at adam.pika.mit.edu
Thu Aug 17 15:56:27 AEST 1989


In article <1140 at midgard.Midgard.MN.ORG> dal at midgard.Midgard.MN.ORG (Dale Schumacher) writes:
>In the <stdio.h> header file, the v[fs]printf() function prototypes
>use the va_list type, but va_list is not defined anywhere in <stdio.h>.

In article <10720 at smoke.BRL.MIL> gwyn at brl.arpa (Doug Gwyn) writes:
>The answer is that the implementor of
><stdio.h> must not attempt to use "va_list" but instead should just
>use the actual type expressed without use of typedefs.

...which is difficult if the implementor of <stdio.h> is not also
the implementor of <stdarg.h>.

In article <2095 at dataio.Data-IO.COM> bright at dataio.Data-IO.COM (Walter Bright) writes:
>1. In stdio.h, include the lines:
>	#ifndef __STDARG_H		/* #define'd by stdarg.h	*/
>	#include <stdarg.h>		/* get definition of va_list	*/
>	#endif

This is the right idea, although it assumes that <stdarg.h>
#defines __STDARG_H, which again an independently-written
<stdio.h> can't do.  (The #ifndef isn't really necessary;
<stdarg.h> can independently protect itself against multiple
#inclusion, albeit at the cost of an extra open, which some
people worry about.)  Anyway, it's illegal for a second reason:

In article <10739 at smoke.BRL.MIL> gwyn at brl.arpa (Doug Gwyn) writes:
>No, don't do this.  <stdio.h> is not allowed to define the va_* macros.

If I were the implementer of both <stdio.h> and <stdarg.h>, I'd
shake my head at this conflicting set of requirements, take a
deep breath, and add something like va_list.h:

	#ifndef _VA_LIST
	#define _VA_LIST
	typedef int *__va_list;
	#endif

<stdarg.h> would then contain

	#include <va_list.h>
	typedef __va_list va_list;

and <stdio.h> would contain

	#include <va_list.h>
	extern int vfprintf(FILE *, char *, __va_list);

(I'd probably have to do the same thing for off_t, because
if fseek() doesn't take one, it should.  Schade, off_t is in
1003.1's baliwick, not X3J11's.)  This is, I'll admit, fussy,
but the rule against defining things in two places (so that an
eventual change must then be made in two places) is an extremely
good one, which I'll break only under extreme duress.

Besides the possible compilation speed degradation due to the
extra file-opening overhead, which Walter will remind me of if
somebody else doesn't, this solution is distasteful because the
prototype

	extern int vfprintf(FILE *, char *, __va_list);

is not "obviously" compatible with the call

	va_list argp;
	...
	vfprintf(fd, fmt, argp);

(Doug's suggestion to use the underlying va_list type directly
in the vfprintf prototype has the same difficulty).  "Obvious"
compatibility is desirable, among other reasons, because header
files containing prototypes are a convenient source of on-line
documentation.

Now, I know that a __va_list is really the same as a va_list,
and in fact the pANS guarantees it (typedefs are merely type
synonyms, not new types), but it still seems unfortunate, if only
because it's another nail in the coffin for that last sentence of
chapter 6 of K&R I:

	Finally, there is always the possibility that in the
	future the compiler or some other program such as lint
	may make use of the information contained in typedef
	declarations to perform some extra checking of a program.

Of course, the pANS typedef definition (which merely codifies
existing practice) has irreversibly sealed that coffin already,
and I doubt that anyone else remembers or cares about the quote
above anyway.

The correct vfprintf prototype in <stdio.h> is in any case only
barely workable for implementers of both <stdio.h> and <stdarg.h>
(i.e compiler and/or RTL vendors).  It is apparently impossible
to write a correct, standalone <stdio.h>, which is what Dale
Schumacher is trying to do.  (It happens that I am trying to do
the same thing, but had not worried about prototypes.  Alas!,
I have not posted my efforts yet, so Dale and I are duplicating
each other's work.)

Am I the only one who gets the same sort of feeling about
function prototypes as about symbolic links: a nice idea, but
introducing enough complications in practice that maybe they're
not so wonderful after all?  (Don't respond telling me what
prototypes are good for; I know what they're supposed to be good
for.)

Also in article <10720 at smoke.BRL.MIL>, Doug writes:
>Warning!  Use __iob or _Iob, not _iob, in your <stdio.h>.

I'm not sure what is implied here.  It seems to me that _iob is
no more reserved that any other reserved identifier.  I'm
deliberately calling my buffer list _iob, to afford the
possibility of compatibility with previously-compiled object
files.  (Yes, this possibility is fraught with peril; and yes,
I like playing with fire.)  Using a different identifier might
conceivably avoid a conflict with a system-defined _iob (by
"system" I mean the complete C RTL that the purported standalone
stdio is attempting to augment), but there are enough other name
conflicts ("printf," etc.) that if any part of the "standard"
stdio gets linked in (_iob or otherwise) there's bound to be
trouble.  (I wish the pANS could drop the "p" sometime soon so
I could get a copy; Doug's point may just have to do with the
distinction between single and double leading underscores or
something.)

                                            Steve Summit
                                            scs at adam.pika.mit.edu



More information about the Comp.lang.c mailing list