Calling FORTRAN subroutines and functions from C/C++ and vice versa

This is a recurring theme in a vast number of scientific applications. FORTRAN was the language of choice of most scientists. Therefore, many venerable and important pieces of software are written in FORTRAN. To illustrate how pervasive this is, I was recently made aware of the IRI model, which stands for International Reference Ionosphere. Although written in the late 70’s, it is still widely used in Space Research. Porting these applications to another language, say C, is a mayor undertaking, and not necessary. FORTRAN subroutines or functions can namely be called from any C/C++ program and vice versa.

Calling a FORTRAN subroutine or function from C/C++

Say you have this FORTRAN function,

      PRECISION FUNCTION ADD2(A,B)
      IMPLICIT NONE
      DOUBLE PRECISION A,B
      ADD2=A+B
      RETURN
      END

To call this function from a C/C++ program,

#include <stdio.h>

double add2_(double *, double *);

int main() {
  double a = 5.0, b = 3.0;
  printf("%f\n",add2_(&a,&b));
  return 0;
}

Notice the underscore after the function name. The underscore signals to the compiler that add2 is an external name.

The codes are compiled but not linked, and then the objects are linked,

$ gfortran -c add2.f
$ gcc -c main.f
$ gcc -o add2 add2.o main.o
$ ./add2
8.000000

FORTRAN passes parameters by reference only. A workaround is to define a wrapper function,

#include <stdio.h>

double add2_(double *, double *);

/* C wrapper to FORTRAN function add2 */
double f_add2(double a, double b) {
  return add2_(&a,&b);
}

int main() {
  printf("%f\n",f_add2(2.0,3.0));
  double a = 7.0, b = 2.0;
  printf("%f\n",f_add2(a,b));
  return 0;
}

The wrapper function f_add2(), defined however is necessary, calls the FORTRAN function add2, instead of being called from main(), or any other function.

$ gcc -c main.f
$ gcc -o add2 add2.o main.o
$ ./add2
5.000000
9.000000

My personal convention if to prepend a f_ to the name of a wrapper in case it is calling a FORTRAN routine/function, and a c_ in case a FORTRAN program is calling a C/C++ wrapper.

Let’s turn the FORTRAN function into a subroutine,

      SUBROUTINE ADD2(A,B,C)
      IMPLICIT NONE
      DOUBLE PRECISION A,B,C
      C=A+B
      RETURN
      END

Important to remember is that FORTRAN subroutines have no return value,

#include <stdio.h>

void add2_(double *, double *, double *);

int main() {
  double a = 1.0, b = 3.0, c;
  add2_(&a,&b,&c);
  printf("%f\n",c);
  return 0;
}  

and so the declaration type has to be void.

The can be changed with the aid of a wrapper,

#include <stdio.h>

void add2_(double *, double *, double *);

/* C wrapper to FORTRAN subroutine add2 */
double f_add2(double a, double b) {
  double c;
  add2_(&a,&b,&c);
  return c;
}

int main() {
  double a = 1.0, b = 3.0, c;
  c = f_add2(a,b);
  printf("%f\n",c);
  printf("%f\n",f_add2(3.0,3.0));
  return 0;
}

Calling a C/C++ function from FORTRAN

The C/C++function,

void add2_(double *a, double *b, double *c) {
  *c = *a + *b;
  return;
}

is called from FORTRAN as if a subroutine,

      PROGRAM MAIN
      IMPLICIT NONE
      DOUBLE PRECISION A,B,C
      A = 7.0
      B = 5.0
      CALL ADD2(A,B,C)
      PRINT *,C
      END  

Notice that the C/C++ function name ends with an underscore, whereas the underscore is absent when calling the function from FORTRAN. The C/C++ function has no return value.

Compile and link,

$ gfortran -c program.f
$ gcc -c add2.c
$ gfortran -o add2 program.o add2.o
$ ./add2 
   12.000000000000000

Likewise, the C/C++ function,

double add2_(double *a, double *b) {
  return *a + *b;
}

is used as if a FORTRAN function,

      PROGRAM MAIN
      IMPLICIT NONE
      DOUBLE PRECISION A,B,C
      DOUBLE PRECISION ADD2
      A = 3.0
      B = 8.0
      C = add2(A,B)
      PRINT *,C
      END
$ gcc -c add2.c
$ gfortran -c program.f
$ gfortran -o add2 program.o add2.o
$ ./add2 
   11.000000000000000

The C/C++ function,

double add2_(double a, double b) {
  return a + b;
}

will need a wrapper,

double add2_(double a, double b) {
  return a + b;
}

double c_add2_(double *a, double *b) {
  return add2_(*a,*b);
}

to be called by a FORTRAN program,

      PROGRAM MAIN
      IMPLICIT NONE
      DOUBLE PRECISION A,B,C
      DOUBLE PRECISION C_ADD2
      A = 3.0
      B = 8.0
      C = c_add2(A,B)
      PRINT *,C
      END

because the C/C++ function does not pass the parameters by reference.

Suppress underscoring

If your function types are fixed, underscoring of function names can be suppressed,

double add2(double a, double b) {
  return a + b;
}

double c_add2(double *a, double *b) {
  return add2(*a,*b);
}

by the use of the -fno-underscoring FORTRAN compiler option.

$ gcc -c add2.c
$ gfortran -fno-underscoring -c program.f
$ gfortran -fno-underscoring -o add2 program.o add2.o
$ ./add2 
   11.000000000000000

This is however not recommended. Underscoring is used by many FORTRAN compilers and ensures compatibility across vendors.

Leave a Reply

Your email address will not be published.