The first example shows how a Fortran subroutine is declared and called from a C++ program. The Fortran subroutine is compiled using the GNU compiler with gfortran -c functions.f90 or using the Intel compiler with ifort -c functions.f90.
! functions.f90 subroutine hello() implicit none ! print *, "Hello from Fortran!" end subroutine hello
The main program is written in C++. The interface between Fortran and C++ requires a C wrapper. Note the underscore in the C wrapper and the function call. In contrast to C++, Fortran does not distinguish between capital and lowercase letters. For a matching function declaration, the C wrapper must use lowercase letters and append an underscore to the Fortran function name.
// main.cpp extern "C" { void hello_(); } int main(int argc, char **argv) { hello_(); return 0; }
The file main.cpp is compiled with g++ -c main.cpp. The linker is invoked with g++ main.o functions.o -lgfortran. The corresponding commands for the Intel compiler are icpc -c main.cpp and icpc main.o functions.o -lifcore, respectively.
The second example addresses Fortran's call-by-reference paradigm. The following Fortran function takes a vector and its length as input parameters, adds all elements of a vector and returns the sum.
double precision function sumVector(n, v) implicit none ! Argument list integer, intent(in) :: n double precision, intent(in) :: v(n) ! ! Add all vector elements. sumVector = sum(v) end function sumVector
Any argument passed to a Fortran function is passed by reference. This includes all primitive data types, which are typically passed by value in C. Consequently, the C++ driver uses the address operator to pass the integer len. The array is already a pointer and can therefore be passed directly.
#include <iostream> using namespace std; extern "C" { double sumvector_(const int *n, double *v); } int main(int argc, char **argv) { int len = 100; double *v = new double[len]; // Initialise. for (int i = 0; i < len; i++) v[i] = i*1.25; double sum = sumvector_(&len, v); cout << "sum = " << sum << endl; delete[] v; return 0; }
The third example passes a matrix to the Fortran subroutine, which multiplies each entry of the matrix with a scalar. The C++ driver passes the start address of the two-dimensional array; the Fortran subroutine interprets the contiguous chunk of memory as an n-by-m matrix. Fortran uses column-major storage for higher-dimensional arrays, whereas C++ uses row-major order. The C++ driver initialises the matrix in column-major order (note the order of the loops) in order to have a consistent memory layout.
subroutine scaleMatrix(n, m, A, alpha) implicit none ! Argument list double precision, intent(inout) :: A(n, m) integer, intent(in) :: n integer, intent(in) :: m double precision, intent(in) :: alpha ! ! Scale n-by-m matrix A with scalar alpha A = alpha * A end subroutine scaleMatrix
int n = 4, m = 5; double A[n][m]; // Initialise in column major format. int cnt = 0; for (int j = 0; j < m; j++) for (int i = 0; i < n; i++) A[i][j] = ++cnt; double alpha = 0.25; scalematrix_(&n, &m, &A[0][0], &alpha);