next up previous
Next: 5- Input/Output Up: Interfacing Fortran and Previous: 3- Argument Passing

4- Calling Fortran from C

Calling a Fortran routine from C is basically the reverse operation of providing a C routine which is Fortran callable. One has to know the correct spelling for the external identifier, for numeric variables pass the address instead of the value itself, and for CHARACTER items construct the appropriate argument list.

We continue to use the example of a subroutine with the same calling sequence SUB(X,CH,Y). In the following code fragments we assume that

  REAL  x, y;
  char* ch_ptr;
  int   ch_len;

are already filled and that we want to pass their values to Fortran. Again the platform dependence in passing character data causes the main difficulty.

VMS

On VMS we have to fill the elements of the string descriptor and then pass its address:

#include <descrip.h>

  struct dsc$descriptor_s ch_dsc;
  ch_dsc.dsc$b_dtype   = DSC$K_DTYPE_T;
  ch_dsc.dsc$b_class   = DSC$K_CLASS_S;
  ch_dsc.dsc$w_length  = ch_len;
  ch_dsc.dsc$a_pointer = ch_ptr;
  Sub( &x, &ch_dsc, &y );

Cray

On Cray a predefined macro packs the address and length information into a cft77 descriptor:

#include <fortran.h>

  Sub( &x, _cptofcd(ch_ptr,ch_len), &y );

NeXT

  Sub(        &x,  ch_ptr,        &y,
       (sizeof x), ch_len, (sizeof y) );

Apollo ftn

The byte ordering of the Motorola-68k CPU does not allow the passing of the address of a 4-byte int if a 2-byte short is expected. Therefore for the Apollo ftn compiler we have to use an auxiliary short:

  short ch_ref = ch_len;
  Sub( &x, ch_ptr, &y,
          &ch_ref );

Others

For all other compilers except IBM-C/370 the call is straightforward:

  Sub( &x, ch_ptr, &y,
           ch_len );

C/370

The IBM C/370 compiler does not allow to call a VS-Fortran routine with CHARACTER arguments. The naive approach

#pragma linkage(SUB,FORTRAN)

  int x_size = (sizeof x);
  int y_size = (sizeof y);
  Sub( &x,       ch_ptr, &y,
       &x_size, &ch_len, &y_size );

does not work. VS-Fortran passes the argument count implicitly by setting the sign bit of the last word in the argument block. uses argument blocks containing the reference addresses.

For routines with CHARACTER arguments both the words at positions N and 2N must be flagged. The #pragma linkage instructs the C compiler to create a Fortran-style argument block with the last word flagged. Unfortunately there is no way to set the sign bit also in the middle of the argument block. Attempts to patch the argument list such as

  REAL* y_ref = 
    (REAL*)(0x80000000 | (int)&y);
  Sub( &x,       ch_ptr,  y_ref, 
       &x_size, &ch_len, &y_size );
do not succeed. (It seems that C/370 clears the sign bit again before storing the address into the argument block.)

The work-around is to use a wrapper routine which receives the character arguments as Hollerith data and copies them into temporary CHARACTER variables. For example,

#pragma linkage(K77XCX,FORTRAN)
#pragma linkage(SUB,FORTRAN)
extern SUBROUTINE SUB;

  SUBROUTINE* sub_ptr = SUB;
  K77XCX( &sub_ptr, &x, ch_ptr, &ch_len, &y );

with

      SUBROUTINE K77XCX(SUB,X1,K2,L2,X3)
      EXTERNAL SUB
      PARAMETER(MBIG=256)
      CHARACTER*(MBIG) C2
      CALL UHTOC(K2,4,C2,L2)
      CALL SUB(X1,C2(:L2),X3)
      CALL FMEMCPY(K2,C2(:L2))
      END

Obviously, MBIG should be set to the maximum string length ever expected. FMEMCPY is a Fortran callable version of memcpy provided by KUIP. The CHARACTER data has to be copied back into the C string in case that it is an output parameter. (UCTOH cannot be used because there the number of bytes copied is rounded up to the next multiple of 4.)

The disadvantage is that each type of argument list requires its own wrapper. This is not foreseen in the cfortran.h approach and is the reason why it cannot be used for C/370.



next up previous
Next: 5- Input/Output Up: Interfacing Fortran and Previous: 3- Argument Passing



Janne Saarela
Mon May 22 15:43:10 METDST 1995