prototypes required ?

Chris Torek chris at mimsy.umd.edu
Sat Oct 20 00:07:35 AEST 1990


In article <2150 at lupine.NCD.COM> rfg at NCD.COM (Ron Guilmette) writes:
>Now please excuse my almost total ignorance regarding the x3j11
>requirements regarding the contents of include files, but ...

To aid in the confusion, note that ANSI C makes no requirements at
all of this sort (since it nowhere requires that there be any files
at all).  The requirements are not `contents of include files' but
rather `behaviour of the compiler upon seeing ``#include <stdio.h>'' '
(and other standard headers).

If we consider `conventional Unix implementations', however:

>I don't immediately see where (in 4.9.1) it says (explicitly) what
>function are required to be declared within <stdio.h>.  Are all of
>the function listed in 4.9.4 thru 4.9.10 required to have declarations
>within <stdio.h>?  If so, are they required to have prototyped
>declarations?

Yes, and yes (unless the compiler implements them as `built in functions'
that are somehow enabled by the `#include').

>... on a machine for which the va_list type is a structure ... I
>encountered an odd problem. ... as it turned out, the creators of
>the <stdio.h> file in question had cheated and put a declaration
>like the following in it:
>
>	int vfprintf (FILE *, const char *, void *);

(but the type of `va_list' is not `void *').

>Obviously, that last formal parameter type is not correct!  That's why I
>got an error at the call.

As it happens, `void *' is `good enough' to hold any pointer type.
This machine's <stdio.h> contains a questionable, but legal, prototype
for vfprintf (provided that it *works* of course).  If the compiler
generates warnings, it can still be considered ANSI conformant---the
standard says nothing about excessive warnings.  Nonetheless, I
personally would like to know about such compilers that I might avoid
them entirely.

>I tried changing the last formal type to (a more correct) `va_list', but
>when I did that this changed the <stdio.h> file into something that could
>*not* be included ALL BY ITSELF into *any* given file.  Rather, it now always
>had to be preceeded by a #include <stdarg.h>.
>
>So what it the `correct' thing to have in the <stdio.h> file regarding the
>vfprintf function (and friends)?

This is one of those sticky implementation issues the ANSI standard
leaves up to the implementor.

Doug Gwyn has in the past suggested something along these lines:

	/* stdarg.h extract */
	typedef int va_list[3];

	/* stdio.h extract */
	int vfprintf(FILE *, const char *, int *);

where <stdio.h> `knows' what the stdarg.h va_list type is.  This makes
<stdio.h> machine-dependent; I consider this to be bad practise.

The 4.3BSD-reno release <std*.h> headers use a different mechanism.
A single file, <machine/machtypes.h>, contains all the machine-dependent
type definitions, using the `hidden' (reserved to implementor) name
space, and usually using preprocessor macros.  For instance, the
<machine/machtypes.h> for a VAX reads (abbreviated):

	#ifndef	_MACHTYPES_H_
	#define	_MACHTYPES_H_
	#define	_PTRDIFF_T_	int			/* ptr1 - ptr2 */
	#define	_VA_LIST_	char *			/* va_list */
	#define	_WCHAR_T_	unsigned short		/* wchar_t */
	#define	_SIZE_T_	unsigned int		/* sizeof() */
	#define	_CLOCK_T_	unsigned long		/* clock() */
	#define	_TIME_T_	long			/* time() */
	#endif

and <stdio.h> then says, in part,

	#include <machine/machtypes.h>
	#ifdef	_SIZE_T_
	typedef	_SIZE_T_ size_t;
	#undef	_SIZE_T_
	#endif
     /* some declarations deleted */
	int vfprintf(FILE *, const char *, _VA_LIST_);

while <stdarg.h>, in part,

	#include <machine/machtypes.h>
	typedef _VA_LIST_ va_list;

On a machine requiring a pointer to a structure, <machine/machtypes.h>
might read in part:

	typedef struct __va_list { /* contents */ } _VA_LIST_;

and no changes to any of the machine-independent headers are necessary.

The funny business with _SIZE_T_ is there so that <string.h> can also
contain a typedef for size_t, yet including both <stdio.h> and <string.h>
still works.  SunOS 4.x releases have the typedefs done directly in
a separate header, but this is erroneous, as it means that the
following conforming program fragment fails to compile:

	#include <string.h>
	nlink_t(const char *s) { return (strlen(s) > 10); }
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris at cs.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.std.c mailing list