2 Cookbook

 2.1 Calling C from FORTRAN
 2.2 Calling FORTRAN from C
 2.3 Building the Program

This section introduces mixed language programming. It skips over many of the details and concentrates on how to get programs going. For a fuller explanation of mixed language programming, you should read the rest of this document.

2.1 Calling C from FORTRAN

Why would you want to call a C function from a FORTRAN program? Typically this will be to do something in the C function that cannot be done from FORTRAN, at least not in the way that you would like. On account of this, realistic examples of calling C from FORTRAN can be rather involved. After all, you can do most simple things from FORTRAN itself. So as not to obscure how to go about writing mixed language programs with complex C functions, the examples in this section concentrate on what to do when mixing C and FORTRAN rather than on providing realistic examples of this.

Here is an example of a FORTRAN program that calls a C function which sets various arguments.

Example 1 – Calling C from FORTRAN.
FORTRAN program:
        PROGRAM COOK1
        INTEGER I,J
        REAL A,B
        CHARACTER*(80) LINE
        LOGICAL X
  
        I = 1
        A = 5.0
        X = .FALSE.
        LINE = ’ ’
        CALL SILLY1( A, B, I, J, LINE, LEN(LINE), X )
        PRINT *, LINE
  
        END

C function:
  #include "f77.h"
  
  F77_SUBROUTINE(silly1)( REAL(a), REAL(b), INTEGER(i), INTEGER(j),
    CHARACTER(line), INTEGER(line_l), LOGICAL(x) TRAIL(line) )
  {
    GENPTR_REAL(a)
    GENPTR_REAL(b)
    GENPTR_INTEGER(i)
    GENPTR_INTEGER(j)
    GENPTR_CHARACTER(line)
    GENPTR_INTEGER(line_l)
    GENPTR_LOGICAL(x)
  
    char str[] = "This is a string";
  
    if( F77_ISTRUE(*x) )
    {
       *b = *a;
       *j = *i;
    }
    else
    {
       cnfExprt( str, line, *line_l );
    }
  }

This is a rather silly example, but it does illustrate all of the important points of calling C from FORTRAN. The FORTRAN program is completely standard. The name of the C function is declared using a macro F77_SUBROUTINE. Do not leave any spaces around the name of the routine as this can cause problems on some systems. The dummy arguments of the function are declared using macros named after the FORTRAN type of the actual argument. The only odd thing is the macro called TRAIL. Each argument of type CHARACTER should have a corresponding TRAIL added to the end of the argument list. N.B. TRAIL macros must not have a comma in front of them. All C functions that are to be called from FORTRAN should be declared in a similar manner.

There then follows a set of GENPTR_type macros; one for each argument of the function. TRAIL arguments are not counted as being true arguments and so there are no GENPTR statements for them. Note that there are no semicolons at the end of these lines.

The only other macro used is F77_ISTRUE. This should be used whenever an argument is treated as a logical value, and takes into account the different ways that FORTRAN and C may interpret bit patterns as logical values.

Note that all explicit function arguments are pointer arguments. This is necessary if their value is to be modified in the function. The consequence of this is that scalar arguments must be referred to by *arg within the function.

FORTRAN and C store character strings in different ways. FORTRAN stores them as fixed-length, blank-filled strings while C stores them as variable-length, null-terminated strings. If a C function needs to work with character strings that have been passed from a calling FORTRAN routine, then the FORTRAN string must be copied into an equivalent local copy. Similarly, a C function may need to return a string to the calling FORTRAN routine. This is a very common occurrence, so some “CNF functions” are provided to do this. Essentially they are just C functions which copy a FORTRAN string to a C string and vice versa. (They are more fully described in Section 6.1.)

In the above example, the function cnfExprt copies the C string str into the FORTRAN string line. Function cnfImprt performs the converse operation in “Calling FORTRAN from C” example in Section 2.2.

2.2 Calling FORTRAN from C

Why would you want to call a FORTRAN subprogram from a C routine? Typically this would be because you want to use a precompiled library of routines that were written in FORTRAN. The NAG library is a prime example. This can be bought in a C callable version, but this is not available on Starlink machines.

To see how to call FORTRAN from C, let us consider the above example, but now with the roles of FORTRAN and C exchanged.

Example 2 – Calling FORTRAN from C.
C program:
  #include "f77.h"
  
  #define FLINE_LENGTH 80
  
  extern F77_SUBROUTINE(silly2)( REAL(a), REAL(b), INTEGER(i), INTEGER(j),
    CHARACTER(line), INTEGER(line_l), LOGICAL(x) TRAIL(line) );
  
  main()
  {
    DECLARE_INTEGER(i);
    DECLARE_INTEGER(j);
    DECLARE_INTEGER(fline_l);
    DECLARE_REAL(a);
    DECLARE_REAL(b);
    DECLARE_LOGICAL(x);
    DECLARE_CHARACTER(fline,FLINE_LENGTH);
  
    char line[FLINE_LENGTH+1];
  
    fline_l = FLINE_LENGTH;
  
    i = 1;
    a = 5.0;
    x = F77_FALSE;
  
    F77_CALL(silly2)( REAL_ARG(&a), REAL_ARG(&b), INTEGER_ARG(&i),
      INTEGER_ARG(&j), CHARACTER_ARG(fline), INTEGER_ARG(&fline_l),
      LOGICAL_ARG(&x) TRAIL_ARG(fline) );
  
    cnfImprt( fline, FLINE_LENGTH, line );
  
    printf( "%s\n", line );
  }

FORTRAN function:
        SUBROUTINE SILLY2( A, B, I, J, LINE, LINE_L, X )
        REAL A, B
        INTEGER I, J
        CHARACTER * ( * ) LINE
        INTEGER LINE_L
        LOGICAL X
  
        IF( X ) THEN
          B = A
          J = I
        ELSE
           LINE = ’This is a string’
        END IF
  
        END

In the above C main program, the variable fline_l is declared and set equal to the constant FLINE_LENGTH. At first sight this is unnecessary. However, this is not the case, as we need to pass the value of FLINE_LENGTH to the subroutine and it is not possible to pass constants to FORTRAN subroutines. Only variables can be passed.

2.3 Building the Program

The final step is compiling and linking the program.

Suppose, on Unix, the main FORTRAN program is in the file cook1.f and the C function is in the file silly1.c, then the commands might be:

  % cc -c -I/star/include silly1.c
  % f77 cook1.f silly1.o -L/star/lib ‘cnf_link‘

Note that the compiling and linking commands are somewhat machine-specific – compiling the FORTRAN routine first and then trying to link the routine using the cc command generally does not work. More details are given in Compiling and Linking (see Section 13).

Armed with the above examples, you should be in a position to start experimenting with mixed language programming. For further information, read on.