Because there are so many reliable subroutine libraries written in Fortran, you will sometimes need to call a Fortran routine from C. Likewise, you might need to call a low-level C routine from a Fortran program.
For a detailed overview of such `mixed language
programming', see SUN/209,
CNF and F77 Mixed Language Programming, which
gives a detailed introduction to calling each language
from the other, as well as a set of C macros to help
support this. I will not duplicate the contents of that
guide, but instead give a very compressed introduction to
the problem. This might be enough to get you going.
There is a further discussion of the issues, and a
compressed description of the solutions, at the Cambridge
High Performance Computing Facility (HPCF), at
<http://www.hpcf.cam.ac.uk/mixed.html>
. For a
Sun-specific discussion, see Chapter 12 of
[sunf77].
The biggest difference between C and Fortran is that `C
is call-by-value, Fortran is call-by-reference'. What
that means is that when a C function is called, it
receives the values of its arguments, so that any
changes to them disappear when the function finishes, but
when a Fortran function is called, it receives a
reference to its arguments, so they can be
altered easily within the function. The consequence of
this is that when you call a Fortran function from C, you
should pass arguments using C's address-of
operator,&
, and when you call a C
function from Fortran, you will typically need to pass it
the value of the variable using the
%val()
function (this is a non-standard VAX
Fortran extension, but one which is now so ubiquitous that
it's safe to use). These remarks apply to unstructured
types such as characters, integers and floats -- arrays
and strings present other problems, as described below.
It follows from what I've said that if a C function is
declared as void subr (int *p)
, it's
expecting (the value of) a pointer to an integer, so that
this could be called in the `normal' way from fortran:
call subr (ia)
, where ia
is an
integer variable.
See Appendix A.6 for example programs.
Fortran's arrays are simple: an array of any dimension
is just a list of locations in memory, stored in the
order a(1,1)
, a(2,1)
, and so
on (see Section 2.5.2.2); when a Fortran function
is given an array argument, what it actually receives is
a pointer to the `top-left' element. If you're calling
Fortran from C, you simply have to be aware of the
switch on order, and then pass
&a[0][0]
.
If you have a C routine with a one-dimensional array
argument (either void func (int a[])
or
void func (int *a)
), and you want to call
it from Fortran, you can call it simply by giving the
array name as an argument: call func (a)
.
Passing a multi-dimensional array to a C
function is potentially problematic. However, you'll
almost never need to do that, because Fortran very
rarely needs to invoke C to do a numerical calculation.
If the C declaration is func (int a[][3])
,
for example (that is, an array of three-element arrays),
then a Fortran array integer a(3,
)
could be
passed simply, as call func (a)
. If, on
the other hand, the C declaration were func (int
**a)
(that is, a pointer to pointer to integer,
with the actual array elements separately allocated),
then the above Fortran array could not be
passed as shown (and no, smarty, call func
(%loc(a))
wouldn't work, even though it's the
right type). If you do need to call such a C
function, you'll probably have to provide a suitable C
wrapper for it, and call that from the Fortran code.
C's array/pointer syntax is elegant, but not ideally
suited for numerical work[Note 10].
C strings are simple objects: they are by definition arrays of characters, with the end of the string marked by a zero byte. The internal structure of Fortran strings is not defined, so that they could be stored in whichever way is most convenient to the author of the compiler; typically, however, they are an array of characters with a length encoded with them. The practical upshot of this is that you simply cannot pass strings back and forth between Fortran and C code in a portable way, and it is fortunate that you rarely need to do this. On those occasions when you do need such a facility, you can use a library of conversion routines such as those described in SUN/209.
When a Fortran compiler produces object code,it typically adds an underscore to the end of each function name. That is, the subroutine:
will produce object code with an external symbolsubroutine func1 (i) integer i call func2 (i) end
func1_
calling a subroutine named
func2_
. You must be aware of this when you
compile Fortran code which is to be linked with C
functions. There are two ways of dealing with this.First, you can call this subroutine from C by calling it with the correct name:
int i1; extern void func1_ (int *i); /* call it */ func1_ (&i1);
So far so good. The problem arises when you want to
call C from the Fortran function, since the Fortran
function will expect to link against a function with a
trailing underscore. If the C function is written by
you, then you could provide this, but if it is a library
routine, you will have to tell the compiler not to add
the underscore to the external name when it generates
object code. For Sun's f77
compiler, you
do this with the compiler option
-ext_names=plain
, for the GNU
g77
compiler it is with the
-fno-underscoring
option, and for
f77
on the Alpha, it is -assume
nounderscore
[RW]. Note
that this will apply to all function names in that
module. Sun's compiler also allows you to declare that
a function is in a C module, using a pragma, but this is
obviously non-portable, and so is not recommended. On
this subject, [RW] points out that
to get access to main() via f77 on decs, you need to set
-nofor_main
at link time.
You should, in general, use the Fortran compiler to link the object files into an executable. This calls the linker with all the correct Fortran libraries. It is of course possible to do the same with the C compiler, but requires a much more elaborate call.