Working out the correct way to call a Fortran function from C has proved to be non-trivial, as although there is some documentation out on the web, most of it is neither clear or free of contradictions. The exception is Starlink's CNF and F77 Manual (see link below).

I am using the latest versions of gcc and gfortran for compilation and linking under OS X Snow Leopard. I have also used gcc and gfortran successfully under Linux (CentOS 5.3 64-bit) running on a Parallels virtual machine on my MacBook Pro.

Examples

Oposite are some simple examples to get you started, although experienced programmers might want to look at Starlink's CNF and F77 documentation (see link below):

Fortran functions that receive numeric variables from C

Fortran functions that receive string variables from C

Fortran common block declarations

Compilation and Linking

Note that what works with gcc and gfortran may not work at all with other compilers (other compilers may work by specifying appropriate linker options and/or Fortran run-time libraries).

Obtaining gcc/gfortran

See High Performance Computing for gcc/gfortran downloads for Mac OS X.

Most linux distributions provide a version of gfortran in its native packaging format. The usual command to install is 'yum install gcc-gfortran' or select System > Add/Remove Software from the K Menu (assuming you use KDE). For versions of gcc/gfortran built directly out of the source repository at gcc.gnu.org go to gfortran.org.

Please email me with any suggestions or corrections to these notes.

Useful Links

I found all the following links useful, although with the exception of Starlink's CNF documentation, none of them clearly explained how to pass strings from C to Fortran:

Starlink's CNF and F77 Manual for Mixed Language Programming in Fortran and C tells a programmer how to mix program segments written in Fortran and C in a portable way using the CNF package. It provides information on several levels from a quick how to get started cookbook, down to machine-specific details. The CNF package comprises two sets of software which ease the task of writing portable programs in a mixture of Fortran and C. F77 is a set of C macros for handling the Fortran/C subroutine linkage in a portable way, and CNF is a set of functions to handle the difference between Fortran and C character strings, logical values and pointers to dynamically allocated memory.

C/C++ code calling Fortran routines contains some simple examples.

Using C/C++ and Fortran together. Includes a comparison of Fortran and C/C++ datatypes and arrays. Note that the order of multi dimensional arrays in C/C++ is the opposite of Fortran.

Calling Fortran Subroutines from C/C++ contains some useful notes and points out that an array in C/C++ is indexed starting from 0, whereas in Fortran the index starts at 1.

Fortran and C/C++ Mixed Programming lists some common programming features and how they are implemented in Fortran and C/C++.

Mixing Fortran and C describes how to mix code written in both Fortran and C. It also describes how an interface to each language's functions can be implemented via bridge routines.

Calling Fortran functions from C

Fortran functions that receive numeric variables from C

C

The Fortran function must be declared at the beginning of the C calling function (e.g. main) like this:

      extern void read_(int *small, float *medium, double *large);

Note that we have to pass all variables to Fortran as pointers. Although the function name is not case sensitive in Fortran, it gains an underscore in the C declaration and when it is called:

      read_(&small, &medium, &large);

Fortran

The Fortran function receives the variables as follows:

      SUBROUTINE READ(small,medium,large)

      INTEGER       small
      REAL          medium
      DOUBLE        large

The precise size of these variables depends on your system's architecture (32 bit verses 64 bit), so you need to confirm the correspondence between ints, floats and doubles in C and Fortran on your system. Otherwise, calling a Fortran function from C with numeric variables is straightforward.

Fortran functions that receive string variables from C

C

This is slightly more complicated. The Fortran function must be declared at the beginning of the C calling function (e.g. main) like this:

      extern void load_(char *string, size_t *len_string);

Note that we have to pass all variables to Fortran as pointers. Our string variable is already a pointer, but we have to pass the string's length as a pointer too. Although the function name is not case sensitive in Fortran, it gains an underscore in the C declaration and when it is called:

      len_string = strlen(string); 

      load_(string, &len_string);

Note that in passing the string from C to Fortran we also need to pass the length of the string, hence the use of strlen beforehand (not forgetting to declare the string length variable as a size_t rather than an int).

Fortran

The Fortran function has to be modified to receive a string variable as a byte array (instead of a character string), as well as the string's length:

      SUBROUTINE LOAD(string,len_string)

      BYTE          string(51)
      INTEGER       len_string

Note that the original Fortran function would not have needed an integer variable to store the length of the received string. We also have to add the following to our Fortran function so that it copies the byte array to a string:

      CHARACTER*50  charstr

      WRITE (charstr,'(50a)') (string(i),i=1,len_string)
Note that we specify a byte array that is one byte longer than the Fortran character string. This is for the NULL character that C would have placed at the end of the string. Unfortunately, Fortran pads character strings with spaces, so you might want to use the Fortran TRIM function to get rid of them on output, e.g.
      WRITE(*,'(a,a)'),"This is the string passed from C: ",TRIM(charstr)

Fortran common block declarations

If in your C code you have to reference a variable that is in a Fortran function's common block declaration such as:

      IMPLICIT DOUBLE PRECISION YTEMP,SPEC
      DIMENSION YTEMP(500),SPEC(999)
      COMMON/YTEMP/  YTEMP,SPEC

you need to declare it outside main as a global struct variable in C like this:

struct	{
	double ytemp[500],spec[999];
	} ytemp_;
It should be noted that the use of global variables like this is not good practice (common block declarations are deprecated in Fortran 95), but you may well be stuck with them in the Fortran functions you want to use in your C programme.

Compilation and Linking

Using the latest versions of gcc and gfortran for compilation and linking keep things pretty simple. Compile your C code with gcc and compile your Fortran code with gfortran. Linking with gfortran appears to deal with any run-time library issues. Here is an example makefile:

myprog : myprog.o load.o read.o
	gfortran -o myprog myprog.o load.o read.o

myprog.o : myprog.c
	gcc -c  myprog.c

load.o : load.f
	gfortran -c load.f

read.o : read.f
	gfortran -c read.f
Xgear Copyright © 2010 Paul Ruffle. All Rights Reserved.