10 The IMPORT and EXPORT Macros

We have already seen that character strings and LOGICAL and POINTER variables have to be converted between the different forms used by FORTRAN and C, and the idea of “importing” a FORTRAN value to a C value, and “exporting” a C value to a FORTRAN value has been introduced with the CNF routines..

Potentially all the other types could differ so macros F77_IMPORT_type, F77_IMPORT_type_ARRAY, F77_EXPORT_type and F77_EXPORT_type_ARRAY are defined to copy the data as required – they will use CNF routines where appropriate. An additional type of LOCATOR is allowed for the IMPORT/EXPORT macros to handle character strings used as HDS locators. There are also macros F77_IMPORT_CHARACTER_ARRAY_P and F77_EXPORT_CHARACTER_ARRAY_P to handle the CHARACTER conversion if the C array is an array of pointers to char.

The IMPORT/EXPORT_ARRAY macros have arguments giving pointers to the data and the number of elements to be converted. This is assumed to be sufficient for both single and multi-dimensional arrays.

These macros impose a slight overhead in that they require both the FORTRAN and C variables to be set up and some copying done, even when this is not strictly necessary. However, they do protect against possible future problems and ease the problem of deciding whether and how the import/export should be done.

In the case of arrays, only pointers are copied unless a conversion really is required (as in the case of CHARACTER and LOGICAL arrays, for example).

A complication arises where the actual argument for a FORTRAN subroutine to be called from C is an array which is only returned. In that case, no exporting is required but the FORTRAN array must still be associated with the C array so that the FORTRAN subroutine knows where to store the results. For those types which require genuine conversion, a pointer to the FORTRAN array will have been set when the space was allocated but for others the pointer must be set to point to the actual C array. Macros F77_ASSOC_type_ARRAY are defined to do this where necessary. They are complementary to the F77_CREATE_type_ARRAY macros so you can include both to ensure that the pointer to the FORTRAN array is set correctly.

After use, the memory holding the FORTRAN array should be returned using an F77_FREE_type macro (which will do nothing if the CREATE macros for the type do not allocate space).

So, a C wrapper for the FORTRAN routine str_reset in the section on Handling CHARACTER and LOGICAL arrays could be written as follows:

Example 10 – Use of IMPORT/EXPORT macros.
  #include "f77.h"
  F77_SUBROUTINE(str_reset)( CHARACTER_ARRAY(array),
                             LOGICAL_ARRAY(lin),
                             INTEGER(dim1),
                             INTEGER(dim2),
                             CHARACTER_ARRAY(out),
                             LOGICAL_ARRAY(lout)
                             TRAIL(array)
                             TRAIL(out) );
  
  void strReset( char *array,
                 int array_length,
                 int *lin,
                 int dim1,
                 int dim2,
                 char *out,
                 int out_length,
                 int *lout ) {
  
  DECLARE_CHARACTER_ARRAY_DYN(farray);
  DECLARE_LOGICAL_ARRAY_DYN(flin);
  DECLARE_INTEGER(fdim1);
  DECLARE_INTEGER(fdim2);
  DECLARE_CHARACTER_ARRAY_DYN(fout);
  DECLARE_LOGICAL_ARRAY_DYN(flout);
  int nels;
  
  /* The dimensions of the arrays are being lied about */
  /* calculate the number of elements */
     nels = dim1 * dim2;
  
  /* Set up "given" arguments */
     F77_CREATE_CHARACTER_ARRAY( farray, array_length-1, nels );
     F77_EXPORT_CHARACTER_ARRAY(array, array_length, farray, farray_length, nels);
     F77_CREATE_LOGICAL_ARRAY( flin, nels );
     F77_EXPORT_LOGICAL_ARRAY( lin, flin, nels );
     F77_EXPORT_INTEGER( dim1, fdim1 );
     F77_EXPORT_INTEGER( dim2, fdim2 );
  /* Set up "returned" arguments */
     F77_CREATE_CHARACTER_ARRAY( fout, out_length-1, nels );
     F77_ASSOC_CHARACTER_ARRAY( fout, out );
     F77_CREATE_LOGICAL_ARRAY( flout, nels );
     F77_ASSOC_LOGICAL_ARRAY( flout, lout );
  
     F77_CALL(str_reset)( CHARACTER_ARRAY_ARG(farray),
                          LOGICAL_ARRAY_ARG(flin),
                          INTEGER_ARG(&fdim1),
                          INTEGER_ARG(&fdim2),
                          CHARACTER_ARRAY_ARG(fout),
                          LOGICAL_ARRAY_ARG(flout)
                          TRAIL_ARG(farray)
                          TRAIL_ARG(fout) );
  
     F77_FREE_CHARACTER( farray );
     F77_FREE_LOGICAL( flin );
     F77_IMPORT_CHARACTER_ARRAY( fout, fout_length, out, out_length, nels );
     F77_FREE_CHARACTER( fout );
     F77_IMPORT_LOGICAL_ARRAY( flout, lout, nels );
     F77_FREE_LOGICAL( flout );
  
     return;
  }

and the corresponding main routine would be:
  #include <stdio.h>
  #include "f77.h"
  void strReset( char *array,
                 int array_length,
                 int *lin,
                 int dim1,
                 int dim2,
                 char *out,
                 int out_length,
                 int *lout );
  
  void main(){
  char inarr[3][2][4]={{"Yes","No "},{"   ","   "},{"No ","Yes"}};
  int inarr_length=4;
  char outarr[3][2][4];
  int outarr_length=4;
  int lin[3][2]={{1,0},{1,1},{0,1}};
  int lout[3][2];
  int i,j;
  
     strReset(&inarr[0][0][0], 4, &lin[0][0], 3, 2,
              &outarr[0][0][0], 4, &lout[0][0] );
  
     printf("i j in  lin out lout\n");
     for (j=0;j<3;j++){
        for (i=0;i<2;i++){
           printf("%d %d %c  %s  %c  %s\n",
              i, j, lin[j][i]?’T’:’F’, inarr[j][i],
                    lout[j][i]?’T’:’F’, outarr[j][i] );
       }
     }
  }