Prototypes

Henry Spencer henry at utzoo.uucp
Sun Mar 27 14:08:56 AEST 1988


> ... Declare it in foo.h... When you write foo.c, be sure to include foo.h...
> Indeed, you have stated foo's signature twice.
> However, the compiler should reject an attempt to
> compile foo.c if the two instances do not match.

There is still one headache with this, a more general flaw of foo.h schemes:
significant information is still present in two different files, and keeping
them in step can be a headache (even if failures are detected at compile
time).  I've been experimenting with a simple solution to this that works
moderately well.  It's a variant on the idea of automatically generating
function prototypes from the function code (which isn't simple to do and
doesn't address the other things that one might want to put in a header).
The idea is to imbed the foo.h information in foo.c, marked so that it can
be extracted automatically.  This still means you have to *write* it twice,
but the two instances can be *together*, which makes synchronized changes
much easier.

The particular marking convention I use is based on an extension of another
notation I already use:  beginning all lines of a multi-line comment with
" *" except for a line in the comment at the head of each function describing
the function, which begins with " -".  (This isn't original, although I no
longer remember exactly who gave me the idea.)  So I use "=" to mark a line
meant for foo.h.  This may be obscure without an example, so here's how I
might start an implementation of strcpy() (ignore the leading tabs):

	/*
	 - strcpy - copy string from b to a
	 = extern char *strcpy(char *a, char *b);
	 *
	 * Using algorithm XYZ to run fast on machine ABC.
	 */
	char *
	strcpy(a, b)
	char *a;
	char *b;
	{
		/* ... */

A simple "egrep '^ -'" will give me the "definition" lines for all the
functions, and a slightly more complex bit of code (see below) will build
a suitable header file.  Note that I can put *anything* into the header
file this way, not just function prototypes.  Note also that I can write
ANSI prototypes even for a non-ANSI compiler; my header-file builder takes
an "old compiler" option that comments out the parameter list.  (It also
turns C++-style // comments in the = lines into C comments, because otherwise
it's hard to get C comments onto such lines.)  Without further ado, here's
what I call "mkh"; I recommend it.  (Oh, ignore the -p option, it's still
experimental.)

-----------
X# mkh - pull headers out of C source
XPATH=/bin:/usr/bin ; export PATH
X
Xpeel='	/^ ==*[ 	]/	/\/\//s;//\(.*\);/*\1 */;
X	s/^ ==*[ 	]//'
X
Xegrep='^ =[ 	]'
X
Xfiles=
Xfor a
Xdo
X	case "$a"
X	in
X		-o)		# old (pre-function-prototype) compiler
X		peel='/^ ==*[ 	][^#]/{	/^\([^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1(/*\2*/);
X			}
X			'"$peel"
X		echo '#ifdef __STDC__'
X		echo '#error "header file prepared with mkh -o"'
X		echo '#endif'
X		;;
X
X		-p)		# include private declarations
X		egrep='^ ==*[ 	]'
X		;;
X
X		*)
X		files="$files $a"
X		;;
X	esac
Xdone
X
Xfor f in $files
Xdo
X	egrep "$egrep" $f | sed "$peel"
Xdone
-----------
-- 
"Noalias must go.  This is           |  Henry Spencer @ U of Toronto Zoology
non-negotiable."  --DMR              | {allegra,ihnp4,decvax,utai}!utzoo!henry



More information about the Comp.lang.c mailing list