V10/cmd/f2c/doc/proto

.SH
7. PROTOTYPES
.PP
In ANSI C and C++, a
.I prototype
describes the calling sequence of a function.
Prototypes can save debugging time by helping catch
errors in calling sequences.  The
.CW \%-P
option instructs $f2c$ to emit prototypes for all
the functions defined in the C it produces; specifically,
$f2c$ creates a \fIfile\f(CW.P\fR of prototypes
for each input \fIfile\f(CW.f\fR or \fIfile\f(CW.F\fR.
One can then arrange for relevant prototype files
to be seen by the C compiler.
For instance, if $f2c$'s
header file
.CW f2c.h
is installed as
.CW /usr/include/f2c.h ,
one could issue the UNIX command
.P1
cat /usr/include/f2c.h *.P >f2c.h
.P2
to create a local copy of
.CW f2c.h
that has in it all the prototypes in
.CW *.P .
Since the C produced by $f2c$ always specifies
.P1
#include "f2c.h"
.P2
(rather than
.CW "#include <f2c.h>" ),
the C compiler will look first in the current directory for
.CW f2c.h
and thus will find the local copy that contains the prototypes.
.PP
$F2c$ can also read the prototype files it writes;
one simply specifies them as arguments to $f2c$.
In fact, $f2c$ reads all prototype files before any
Fortran files; although multiple Fortran files are handled
independently, any prototype file arguments apply to all of them.
$F2c$ has more detailed knowledge of Fortran types than it conveys
in the C it puts out; for example,
.CW logical
and
.CW integer
are different Fortran types, but are mapped to the same C type.
Moreover,
.CW character ,
.CW complex ,
and
.CW "double complex"
Fortran functions are all translated to
.CW VOID
C functions, and, unless the
.CW \%-R
option is specified, both
.CW real
and
.CW "double precision"
Fortran functions are translated to
.CW doublereal
C functions.  Because $f2c$ denotes all these
types differently in its prototype files, it
can catch errors that are invisible to an ANSI C
(or C++) compiler.
.PP
The following table shows the types
that $f2c$ uses for procedure arguments:
.TS
center box;
lfCW lfCW.
C_fp	complex
D_fp	doublereal
E_fp	real\fR under \f(CW-!R\fR (the default)\fP
H_fp	character
I_fp	integer\fR or \f(CWinteger*4
J_fp	integer*2
K_fp	shortlogical\fR (\f(CWlogical\fR under \f(CW-i2\fR or \f(CW-I2\fR)\fP
L_fp	logical
R_fp	real\fR under \f(CW-R
S_fp	subroutine\fR
U_fp	\fRuntyped \f(CWexternal
Z_fp	doublecomplex
.TE
These types are defined in
.CW f2c.h ;
they appear in prototypes and, under
.CW \%-A
or
.CW \%-C++ ,
in the C that $f2c$ writes.  Prototypes also use special
.CW void
types to denote the return values of
.CW complex ,
.CW "double complex",
and
.CW character
functions:
.TS
center box;
lfCW lfCW.
C_f	complex
H_f	character
Z_f	double complex
.TE
.PP
$F2c$ also writes special comments in prototype files giving
the length of each
.CW common
block; when given prototype files as arguments, $f2c$ reads
these special comments so it can issue a warning message if its
Fortran input specifies a different length for some
.CW common
block.
.PP
Sometimes people write otherwise valid Fortran 77 that
specifies different lengths for a
.CW common
block.  If such Fortran is split into several files and converted
to C, the loader could end up giving too little space to the
.CW common
block in question.  One can avoid the confusion this could cause by
running $f2c$ twice, first with
.CW \%-P!c ,
then with the resulting prototypes as additional arguments;
the prototypes let $f2c$ determine (and convey to all of its
output C files) the true length needed for
each
.CW common
block.
.PP
One complication with prototypes comes from Fortran subprograms that
declare a procedure to be
.CW external
but do not explicitly specify a type for it and only
pass it as a parameter to another procedure.  (If the
subprogram also invokes the
.CW external
procedure, then $f2c$ can tell whether the procedure is
a subroutine or a function; in the latter case, Fortran's
implicit typing rules specify a type for the procedure.)
If it can do no better, then $f2c$ assumes that untyped
.CW external
procedures are subroutines (and hence become
.CW int -valued
functions in C).
This can cause the generated C to have
multiple and inconsistent declarations for some procedures.
For example,
.P1
	external f
	call foo(f)
	end
	function f(x)
	double precision f, x
	f = x
	end
.P2
results in
.CW MAIN_\|_
declaring
.P1
    extern /* Subroutine */ int f_();
.P2
and in the subsequent definition of
.CW "doublereal f_(x)"
in the same C file.
Such inconsistencies are grounds for some C compilers
to abort compilation.
.PP
$F2c$'s type inferences only apply sequentially to
the procedures in a file, because $f2c$ writes C for each procedure
before reading the next one.  Thus, as just illustrated, if procedure
.CW xyz
comes after
.CW abc
in a Fortran input file, then $f2c$ cannot use information
it gains when it sees the definition of
.CW xyz
to deduce types for
.CW external
procedures passed as arguments to
.CW xyz
by
.CW abc .
By using the
.CW \%-P
option and running $f2c$ several times, one can
get around this deficiency.  For instance, if file
.CW zap.f
contains the Fortran shown above, then the commands
.P1
	f2c -P!c zap.f
	f2c -A zap.[fP]
.P2
result in a file
.CW zap.c
in which
.CW MAIN_\|_
correctly types
.CW f_
and
.CW foo_
as
.P1
    extern doublereal f_();
    extern /* Subroutine */ int foo_(D_fp);
.P2
rather than
.P1
    extern /* Subroutine */ int f_();
    extern /* Subroutine */ int foo_(U_fp);
.P2
The first invocation of $f2c$ results in a file
.CW zap.P
containing
.P1
extern doublereal f_(doublereal *x);
/*:ref: foo_ 10 1 200 */
.P2
The second invocation of $f2c$ is able to type
.CW f_
and
.CW foo_
correctly because of the first line in
.CW zap.P .
.PP
The second line in
.CW zap.P
is a special comment that records the incomplete type
information that $f2c$ has about
.CW foo_ .
$F2c$ puts one such special comment in the prototype file for each
Fortran procedure that is referenced but not defined in the Fortran file.
When it reads prototype files, $f2c$ deciphers these comments and
uses them to check the consistency of calling sequences.
As it learns more about untyped external procedures, $f2c$ updates
the information it has on them; the
.CW :ref:
comments it writes in a prototype file reflect $f2c$'s latest knowledge.
.PP
Ordinarily $f2c$ tries to infer the type of an untyped
.CW external
procedure from its use as arguments to procedures of
known argument types.  For example, if
.CW f.f
contains just
.P1
	external f
	call foo(f)
	end
.P2
and if
.CW foo.P
contains
.P1
extern int foo_(D_fp);
.P2
then
.P1
f2c -A f.f foo.P
.P2
results in the declaration
.P1
    extern doublereal f_();
.P2
Under unusual circumstances, such type inferences
can lead to erroneous error messages or to incorrect typing.
Here is an example:
.P1
	subroutine zoo
	external f
	double precision f
	external g
	call zap(1,f)
	call zap(2,g)
	end
	subroutine goo
	call g
	end
.P2
$F2c$ first infers g to be a double precision function, then discovers
that it must be a subroutine and issues a warning message about
inconsistent declarations for
.CW g .
This example is legal Fortran 77;
.CW zap
could be defined, for instance, by
.P1
	subroutine zap(n,f)
	external f
	if (n .le. 1) call zap1(f)
	if (n .ge. 2) call zap2(f)
	end
.P2
In such a case one can specify the
.CW \%-!it
option to instruct $f2c$ not to infer the types of otherwise
untypable
.CW external
procedures from their appearance as arguments to known procedures.
Here is another (somewhat far-fetched) example where
.CW \%-!it
is useful:
.P1
	subroutine grok(f,g,h)
	external f, g, h
	logical g
	call foo(1,g)
	call foo(2,f)
	call zit(1,f)
	call zit(2,h)
	call zot(f(3))
	end
.P2
Without
.CW \%-!it ,
$f2c$ first infers
.CW f_
to be a
.CW logical
function, then discovers that Fortran's implicit typing
rules require it to be a
.CW real
function.
$F2c$ issues the
warning message
.CW "fixing wrong type inferred for f" '', ``
which should serve as a warning that $f2c$ may have made some
incorrect type inferences in the mean time.
Indeed, $f2c$ ends up typing
.CW h_
as a
.CW logical
function; with
.CW \%-!it
specified, $f2c$ types
.CW h_
as an
.CW external
procedure unknown type, i.e., a
.CW U_fp ,
which to the C compiler appears to be a subroutine.
(Even with
.CW \%-!it
specified, $f2c$ issues a warning message about inconsistent
calling sequences for
.CW foo .)
.PP
Because $f2c$ writes its latest knowledge of types into
prototype files, it is easy to write a crude script
that will glean the maximum possible type information:
.P1
>f.p
until
	f2c -Pit f.p f.f
	cmp -s f.p f.P
do
	mv f.P f.p
	done
.P2
In such scripts, use of the
.CW \%-Ps
option can save an iteration;
.CW \%-Ps
implies
.CW \%-P
and instructs $f2c$ to issue return code 4 if another
iteration might change a declaration or prototype.
Thus the following script is more efficient:
.EQ
delim off
.EN
.P1
while :; do
	f2c -Ps f.[fP]
	case $? in 4) ;; *) break;; esac
	done
.P2
.EQ
delim $$
.EN
The number of iterations depends on the call graph of the
procedures in
.CW f.f
and on their order of appearance in
.CW f.f .
Sorting them into topological order (so that if
.CW abc
calls
.CW def ,
then
.CW abc
precedes
.CW def )
and reverse topological order and alternating between
the two orders
is probably a good heuristic.
For example, we were able to completely type
the \s-2PORT3\s+2 subroutine library
in two passes by first processing it in reverse topological order,
then in forward order.  Unfortunately, one can devise situations
where arbitrarily many iterations are required.  This is slightly
annoying, since with appropriate data structures (in an extensively
reorganized version of $f2c$), one could do this calculation
in linear time.