Next Up Previous Contents
Next: 2.5.5 Compilers, and other stray remarks on code
Up: 2.5 Code topics
Previous: 2.5.3 Debugging
[ID index][Keyword index]

2.5.4 Intermixing Fortran and C

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.

2.5.4.1 Arrays

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,n) 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].

2.5.4.2 Strings

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.

2.5.4.3 Compiling and linking

When a Fortran compiler produces object code,it typically adds an underscore to the end of each function name. That is, the subroutine:


      subroutine func1 (i)
      integer i
      call func2 (i)
      end
will produce object code with an external symbol 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.


Next Up Previous Contents
Next: 2.5.5 Compilers, and other stray remarks on code
Up: 2.5 Code topics
Previous: 2.5.3 Debugging
[ID index][Keyword index]
Theory and Modelling Resources Cookbook
Starlink Cookbook 13
Norman Gray
2 December 2001. Release 2-5. Last updated 10 March 2003