The operations needed to write a C routine that can call a FORTRAN subroutine or function are fairly similar to those needed when calling C from FORTRAN. Many of the macros that are used are the same, so you should read
Section 5 before reading this.
A typical reason to call FORTRAN from C is to use a pre-existing subroutine library. Here is an example of calling PGPLOT from a C main program.
This is a realistic example of calling PGPLOT routines from C. The module begins with a set of
function prototypes for the FORTRAN routines that will be called in the C main program. All
variables that need to be passed to FORTRAN subroutines are declared using DECLARE_type
macros.
These macros ensure that the variables are declared to be of the correct type and storage size expected
by the FORTRAN subroutine. There then follow the calls to the subroutines that do the actual plotting.
The most notable things about these calls is that the actual arguments are explicitly passed by address.
This seems strange to a FORTRAN programmer, but is natural to a C programmer. Arguments that
may be modified must always have their addresses passed, not their values. It may be thought that
the type_ARG
macros should add the &
character where it is needed. However, this gives
rise to problems when calling FORTRAN from C from FORTRAN, as well as being rather
misleading. Note that scalar arguments need the ampersand character adding, whereas
array arguments do not. This is exactly what would be typed if the called routine were a C
function.
What is clear from this example is that the inability to put arguments that are constant expressions
directly in the call to the routine makes the program a lot more verbose than the equivalent FORTRAN
program. Unfortunately, the obvious solution of writing an actual argument as something like
INTEGER_ARG(&5)
does not work as you cannot take the address of a constant. This is not a failing of
the F77 macros, but is inherent in the C language. For routines that are called in many
places, it will be more convenient to write a wrap-up function in C that is to be called
from the C main program and to put all of the F77 macros required into that function. This
produces less efficient code, since there is an extra level of subroutine call. However, in
many situations, the extra cost will be outweighed by the benefits of more transparent
code.
The macro F77_CALL
actually expands to the same thing as the macro F77_EXTERNAL_NAME
, but is
included as it is more descriptive of what is being done when calling a FORTRAN routine from
C.
Fortran code is not thread-safe, and therefore any C code that calls Fortran code will not be thread-safe
unless extra work is done to make it so. The F77_LOCK
macro is provided for this purpose. The
argument to the macro is a block of code to be run. CNF defines a single global pthread mutex. The
F77_LOCK macro firsts locks this mutex, then executes the code specified in its argument, then
unlocks the mutex. If another thread already has the mutex locked, then the calling thread will block
until the mutex is unlocked.
So any C code that may potentially need to be executed in a threaded context (for instance, C wrappers for Fortran subroutine libraries) should use the F77_LOCK macro to invoke each Fortran call:
If this is done consistently, then it ensures that no two threads will attempt to run any Fortran code simultaneously.