Calling Fortran routines from a C++ program in Unix

In general it is possible to call routines written in Fortran from a C++ program. But this should be avoided as it could introduce troubles in porting and maintenance. In any case some hints to allow interfacing are listed in what follows.

The extern "C" directive
First of all, the extern "C" linkage specification must be used to declare any modules that are not written in C++.

Case sensitivity
C++ is a case sensitive language, Fortran is not. All reference to Fortran symbols my be specified in lowercase in C++ calls.

The underscore (_)
In many Fortran compilers, an underscore (_) is appended by default at the end of definitions and references to externally visible symbols (subroutines, functions, etc.). This happens for Solaris and Digital UNIX f77 compilers, for g77 compiler and for hepf77 compiler interface; on HP-UX the +ppu option must be added to the f77 compiler to activate this feature; on AIX -qextname must be added to the xlf compiler. The appended underscore is a standard for HEP Fortran libraries (e.g. CERNLIB). In a C++ call the Fortran subroutines or functions must be specified with an appended underscore.

Passing parameters
An important thing to remember is that C++ passes all parameters by value (except arrays and structures). Fortran passes them by reference. It is therefore necessary to specify in the C++ function prototypes that the Fortran subroutines and functions expect call-by-reference arguments using the address-of (&) operator.

To resume the previous points with an example, consider the Fortran function:

integer function fortranfuntion( a, b )
double precision a, b
...
end

It must be called from C++ as:

// external Fortran function prototype
extern "C" { int fortranfuntion_( double&, double& ); }
...
int main() {
double a, b;
...
int i = fortranfunction_( a, b );
...
}

Arrays
C++ stores arrays in row-major order, whereas Fortran stores arrays in column-major order. The lower bound for C++ is 0, for Fortran is 1. This mean that the Fortran array element myarray(1,1) corresponds to the C++ array element myarray[0][0]; whereas myarray(6,8) corresponds to myarray[7][5];

Fortran Files
Fortran I/O routines require a logical unit number to access a file, C++ accesses files using UNIX I/O routines and intrinsics and requires a stream pointer. A Fortran logical unit CANNOT be passed to a C++ routine to perform I/O on the associate file, NOR CAN a C++ file pointer be used by a Fortran routine.

Fortran Subroutines
C++ does not distinguish between subroutines and functions. All subprograms are treated as functions. Fortran subroutines can be seen as functions not returning a value:

Fortran code
subroutine fortransubr( i )
integer i
...
end

C++ code
// external Fortran function prototype
extern "C" { void fortransubr_( int& ); }
...
int main() {
int i;
...
fortransubr_( i );
...
}

Fortran common areas
Fortran common areas can be accessed by C++ by defining a structure type and a variable of this type to be defined extern (also in this case an underscore must be added at the end of C++ variable related to the Fortran common area):

Fortran code
subroutine mysubr( a );
integer a
integer b(20), c(10)
common /mycommon/ b, c
...
end

C++ code
typedef struct { int b[20]; int c[10]; } mycommonF77;
...
int main() {
int a;
extern mycommonF77 mycommon_;
...
mycommon_.b[3] = 10;
...
}

Fortran strings (character*N)
Fortran character parameters are generally passed by descriptor. C++ char defines simply a byte; in this language, strings are arrays of bytes terminating with a null byte ('\0'). Exchanging string parameters between different languages could introduce additional difficulties in porting. With g77 the libg2c.a must be added at linking time to allow strings exchange. Anyway, in general this should work:

Fortran code
subroutine mysubr( a, size );
character*256 a
integer size
character*256 thestring
...
This is the string that can be used:
thestring(1:size) = a
...
end

C++ code
extern "C" { void mysubr_( const char*, const int& ); }
...
int main() {
char a[] = "this is a string";
int size = sizeof(a);
...
mysubr_( a, size );
...
}

How to compile and link
Obviously the C++ and Fortran source files must be compiled separately using the opportune compiler. Linker must be called via the C++ compiler as the main program lies in the C++ source files:

g77 -c myfortran.f
g++ -o myprogram myprogram.cc myfortran.o -lg2c

A global example
A working example that includes what described above can be found here:

The C++ source: c1.cc

The Fortran source: f1.f

The gnu make file: GNUmakefile


Benigno Gobbo . Last update: 990510