Programming

C-Fortran Interface


You may want to
assemble programs from a mixture of C and Fortran modules. One reason might be to call Fortran graphics routines from the MONGO or PGPLOT libraries from a C program. Another might be to call a C function that manipulates character strings in some way that is ugly, or impossible, in Fortran. Many Unix compilers have a somewhat standard procedure for mixing C and Fortran modules. The procedures decribed here are specific to the Sun operating system, but may carry over to other flavors of Unix.

This discussion is a restatement of material hidden away in the Sun Fortran Programmer's Guide and C Programmer's Guide. We won't discuss the exotic case of a Fortran function that returns a character string, but we will discuss the procedure naming convention, the correspondence between data types, return values, and argument lists.

Naming Conventions

By convention, the Fortran compiler appends an underscore to the names you give for common blocks and procedures. This allows the linker to know how to apply the C-Fortran interface in particular cases. Put an underscore at the end of the name of a Fortran subroutine when you call it from C, and put an underscore after the name in a C declaration to make the function callable from Fortran. That is, the C function declared as void ucase_(...) may be called from Fortran as call ucase(...) Similarly, the Fortran subroutine declared as subroutine matinv(...) may be called from C as matinv_(...)

Data Types and Return Values

The correspondence between C and Fortran data types is summarized in the following table. In the interest of portability, it is fair to point out that the Fortran real declaration can give different results on machines from different vendors, so you might want to explicitly declare reals as real*4.

C and Fortran Data Declarations

Fortran functions returning values of type integer, logical, real, or double precision may be called from C provided that they are declared to be of the corresponding type shown in Table 10.2. Consult the Sun Fortran Programmer's Guide for a discussion of Fortran functions returning values of type complex, double complex, or character, all of which are handled with extra arguments for the corresponding C function. Going the other way, the Sun documentation warns that a C function of type float will actually return a value of type double (unless you resort to a trick).

Arguments

Argument lists need to be handled with care. Neither the C nor the Fortran compiler checks for mismatched argument types, or even a mismatch in the number of arguments. Some bizarre run-time errors therefore arise. Keep in mind that Fortran passes arguments by reference whereas C passes arguments by value. When you put a variable name into a function call from Fortran, the corresponding C function receives a pointer to that variable. Similarly, when calling a Fortran subroutine from C, you must explicitly pass addresses rather than values in the argument list.

When passing arrays, remember that C arrays start with subscript zero. Fortran stores multidimensional arrays in column-major order (first index varies fastest) whereas C stores them in row-major order (last index varies fastest).

Passing character strings is a special problem. C knows it has come to the end of string when it hits a null character, but Fortran uses the declared length of a string. The C-Fortran interface provides an extra argument for each character string in a C argument list to receive the declared length of a string when called from Fortran. Consider the following Fortran fragment:

character*100 string 
call ucase( string )
If ucase were written in C, it might to look like this:

ucase_ ( string, string_len )
char *string; 
long int string_len; { 
  long int string_count;
  string_count = string_len; 
  while( string_count-- != 0 ) { 
    if( *string >= 'a' && *string <= 'z' ) 
      *string++ = *string + 'A' - 'a'; 
    else 
      string = string+1; 
    } 
  }

At the end of the argument list there is an extra argument, of type long int (and not a pointer), for each character string. Of course, it is up to the programmer to make use of these arguments. You have to count your way down each string, rather than relying on a null character as a terminator. And remember that indexes start at zero in C, so *(string+string\string_len) is past the end of the string.

When passing strings from C to Fortran, remember that the name of a string is a pointer. You can use the Fortran built-in function len to retrieve the string length that you put into the argument list in the call from C.

Passing constants from Fortran to C should not cause problems, as long as you use Fortran's implicit rules for deciding how to cast numbers. That is, if no decimal point is found the number will be passed as an integer, if a decimal point is found then the number will be passed as a real unless of the form 1.d0, in which case it is passed as double precision. The logical constant .TRUE. is equivalent to a long int with value one , and .FALSE. is an long int with value zero.

Passing constants from C to Fortran is basically impossible since you can't extract an address to pass (unlike in VAX VMS C, where the compiler will accept &1). The one exception is character strings, since strings are really pointers anyway. For example, see the following:

#include <stdio.h>
main() 
{ 
  char *string="What the hell."; 
  forcheck_( string, 14 ); 
  forcheck_( "What the hell.", 14 ); 
  forcheck_( &string[0], 14 ); 
}
The Fortran subroutine forcheck sees the same string each time. Note that the extra arguments for string lengths are different, since a value rather than an address is expected there.

Command Line Arguments:

You may not be familiar with the C language convention for reading arguments from the command line. Here is the echo program from Kernighan and Ritchie [Kernighan88]:

main( argc, argv ) 
int argc; 
char *argv[]; 
{ 
  while ( --argc > 0 ) 
    printf( (argc > 1) ? "%s " : "%s\n", *++argv ); 
}
The argument count argc is at least one, since the command name itself appears in the argument vector as argv[0]. The argument vector is declared as a pointer to an array of character strings which, at run time, contains the command line arguments, one per string.

In Fortran, use the function iargc() to obtain the argument count, and use the subroutine getarg to read a particular argument from the argument vector to a character string. Here is the example myecho from the Sun documentation:

  character arg*80 
c 
c find out how many command line arguments there are 
nargs = iargc() 
c one at a time, get an argument and write it out 
do 10 i = 1,nargs 
  call getarg( i, arg ) 
  print '(a)', arg 
10 continue 
end
As you would guess, if i=0 then getarg returns the command name.

Linking

If you have a program consisting of both Fortran and C modules, you should use the proper compiler to obtain object modules, and then f77 to pass the object modules to the loader. For example, to compile and link a program consisting of modules main.c and subr.f, do the following:

% cc -c main.c 
% f77 -c subr.f 
% f77 main.o subr.o
Any additional libraries that my be required, like the PGPLOT or MONGO libraries, can be added to the list of these commands.

Naming Conventions
Data Types and Return Values
Arguments
Command Line Arguments:
Linking

Generated with WebMaker