Additional Topics > External Development Guide > Using CALL_EXTERNAL > Fortran Examples

# Fortran Examples

## Example: Calling a Fortran Routine Using a C Interface Routine

Calling Fortran is similar to calling C, with the significant difference that Fortran code expects all arguments to be passed by reference and not by value (the C default). This means that the address of the argument is passed rather than the argument itself. This issue is discussed in By-Value and By-Reference Arguments.

A C interface routine can easily extract the addresses of the arguments from the argv array and pass them to the actual routine which will compute the sum. The arguments f, n, and s are pointers that are being passed by value. Fortran expects all arguments to be passed by reference — that is, it expects all arguments to be addresses. If C passes a pointer (an address) by value, Fortran will interpret it correctly as the address of an argument. The following code segments illustrate this. The `example_c2f.c` file contains the C interface routine, which would be compiled as illustrated above. The example.f file contains the Fortran routine that actually sums the array.

In these examples, we assume that the routines are being compiled under Sun Solaris. The object name of the Fortran subroutine will be sum_array1_ to match the output of the Solaris Fortran compiler. The following are the contents of `example_c2f.c` and example.f:

#include <stdio.h>

void sum_array(int argc, void *argv[])

{

extern void sum_array1_();/* Fortran routine */

int *n;

float *s, *f;

f = (float *) argv[0]; /* Array pntr */

n = (int *) argv[1]; /* Get # of elements */

s = (float *) argv[2]; /* Pass back result a parameter */

sum_array1_(f, n, s); /* Compute sum */

}

f77

c This subroutine is called by SUM_ARRAY and has no IDL-specific code.

c

SUBROUTINE sumarray1(array, n, sum)

INTEGER*4 n

REAL*4 array(n), sum

sum=0.0

DO i=1,n

sum = sum + array(i)

PRINT *, sum, array(i)

ENDDO

RETURN

END

This example is compiled and linked in a manner similar to that used in the C example above. For more information on compiling and linking on your platform, see the README file contained in the `external/call_external/Fortran` subdirectory of the IDL distribution. This directory also contains a makefile, which builds this example on UNIX platforms. To call the example program from within IDL:

;Make an array. X = FINDGEN(10)

;A floating result

SUM = 0.0

S = CALL_EXTERNAL('example.so', $

'sum_array', X, N_ELEMENTS(X), sum)

In this example, example.so is the name of the sharable image file, sum_array is the name of the entry point, and X and N_ELEMENTS(X) are passed to the called routine as parameters. The returned value is contained in the variable sum.

## Hidden Arguments

When passing C null-terminated character strings into a Fortran routine, the C function should also pass in the string length. This extra parameter is added to the end of the Fortran routine call in the C function, but does not explicitly appear in the Fortran routine.

For example, in C:

char * str1= 'IDL';

char * str2= 'ITT';

int len1=3;

int len2=3;

double data, info;

/* Call a Fortran sub-routine named example1 */

example1_(str1, data, str2, info, len1, len2)

In Fortran:

SUBROUTINE EXAMPLE1(STR1, DATA, STR2, INFO) CHARACTER*(*)STR1, STR2

DOUBLE PRECISIONDATA, INFO

## Example: Calling a Fortran Routine Using a Fortran Interface Routine

Calling Fortran is similar to calling C, with the significant difference that Fortran expects all arguments to be passed by reference. This means that the address of the argument is passed rather than the argument itself.

A Fortran interface routine can be written to extract the addresses of the arguments from the argv array and pass them to the actual routine which will compute the sum. Passing the contents of each argv element by value has the same effect as converting the parameter to a normal Fortran parameter.

This method uses the OpenVMS Extensions to Fortran, %LOC and %VAL.

Some Fortran compilers may not support these extensions. If your compiler does not, use the method discussed in the previous section for calling Fortran with a C interface routine.

The contents of the file example1.f are shown in the following figure. This example is compiled, linked, and called in a manner similar to that used in the C example above. For more information on compiling and linking on your platform, see the README file contained in the external/fortran subdirectory of the IDL distribution. This directory also contains a makefile, which builds this example on UNIX platforms.

Note: This example is written to run under a 32-bit operating system. To run the example under a 64-bit operating system would require modifications; most notably, to declare argv as INTEGER*8 rather than INTEGER*4.

f77

SUBROUTINE SUM_ARRAY(argc, argv) !Called by IDL

INTEGER*4 argc, argv(*) !Argc and Argv are integers

j = LOC(argc) !Obtains the number of arguments (argc)

!Because argc is passed by VALUE.

c Call subroutine SUM_ARRAY1, converting the IDL parameters

c to standard Fortran, passed by reference arguments:

CALL SUM_ARRAY1(%VAL(argv(1)), %VAL(argv(2)), %VAL(argv(3)))

RETURN

END

c This subroutine is called by SUM_ARRAY and has no

c IDL specific code.

c

SUBROUTINE SUM_ARRAY1(array, n, sum)

INTEGER*4 n

REAL*4 array(n), sum

sum=0.0

DO i=1,n

sum = sum + array(i)

ENDDO

RETURN

END

To call the example program from within IDL:

X = FINDGEN(10) ; Make an array. sum = 0.0

S = CALL_EXTERNAL('example1.so', $

'sum_array_', X, N_ELEMENTS(X), sum)

In this example, example1.so is the name of the sharable image file, sum_array_ is the name of the entry point, and X and N_ELEMENTS(X) are passed to the called routine as parameters. The returned value is contained in the variable sum.

Note: The entry point name generated by the Fortran compiler may be different than that produced by the C compiler. One of the best ways to find out what name was generated is to use the UNIX nm utility on the object file. See your system’s man page for nm for details.