home
On this document, I explain how to link C/C++ code with program written
in Fortran.
The document is devided into sections each treating an issue that you
may encounter when you link C and Fortran. I shall use as an example a
function defined in fortran. We wish to call this function from C++.
The function definition in Fortran is:
subroutine gagafe(n, r, f, u, ax, ay, az)
integer ncoord
real*8 r(n), f(n), u, ax, ay, az
...
end
In C++ the function defined in Fortran is declared as:
extern "C" void gagafe_(int const * n, double const * r, double* f, double* u, double const * ax, double const * ay, double const * az);
The first thing to do is to find matching types between the two
languages. On the computers I use for example (macintosh PowerPC and
Linux x86) integer is 4 bytes long and
corresponds in C to int or long
(int and long are
the same on those computer). Type real*8
correspond to double in C and is 8 bytes
long. The size of a type can be checked in C by using sizeof.
Example:
cout << "sizeof(double) = " << sizeof(double) << endl;
cout << "sizeof(int) = " << sizeof(int) << endl;
On my computer, it returns:
sizeof(double) = 8
sizeof(int) = 4
There is no guarantee that those types will always match
as their size may differ on different machines. A way to solve the
problem is to use fixed size types. For example Fortran type real*8
has a fixed size of 8 bytes. In C, fixed size integer types are defined
in stdint.h. For example, type int32_t
is a integer of size 32 bits (or 4 bytes). These types are standard in
ISO C99. I did not find any standard fixed size types for floating
numbers.
When you have found the matching types, you must declare the Fortran
function in the C/C++ code. You may have noticed that the variables are
declare as pointers in C++, although they are
used like variables in Fortran. Some pointers
were declared as pointing to constant data (const
keyword).This is only to indicate in the C++ code that those variables
are not changed by Fortran function gagafe.
They do not actually prevent, the variables from being modified by the
fortran code. So be careful.
The extern "C" preceding the function is
only for C++. There would be nothing in C. This is because the name of
the functions once compiled (name of the function in the object file or
.o file) is different from the name of the function in the source code.
In C and Fortran, those names are similar. But in C++, because C++
allows to overload functions, the names of the compiled functions is
the names of the function in the source mixed with something else to
indicate the types of the function parameters. Keyword
extern "C" indicates that we wish the function to be
named like in C. On Unix machines, the command nm
can be used to display the content of an object file. For example, I
used it on my computer with an object file compiled by g77
:
shd16:~/water/source phy$ nm gagafetip4p.o \n
... \n
000007f0 S _gagafe_ \n
... \n
_gagafe_ is the name of my function in the
object file.
You can see on the C++
declaration of gagafe that the function has
an underscore appended. This underscore is not always needed. It
depends on the name of your function and the compiler you are using. To
compile you use the gnu compiler, g++ for C++
and g77 for Fortran. In Fortran, g77
adds two underscores, one at beginning the other at the end of the
function (see nm
gagafetip4p.o). In C, only one underscore is added at the
beginning of the function. The extra underscore in the C++ declaration is to
make the functions match. Note that this underscore is not always
required. For example, if the function names in the source already
contains a underscore the naming for the object works differently.
Other compilers may use different naming convention (e.g. xlf
does not add any undercore at the end). It also depends on the machine
even if you use the same compiler (e.g. gcc).
That is why nm is very useful to check the
functions names with nm to make the function
match. Compilers usually have options to change the naming of the
function (e.g. "-fleading-underscore" and "-fno-leading-underscore"
for gcc, "-funderscoring" for g77,
etc ...). However to make your code more portable, I strongly recommend
to use these options as little as you can and instead to dub your
functions. For example, in my code I had a function called gagafetip4p
written in C that I wanted to call it from Fortran. In the C code I
defined another function:
inline void gagafetip4p_(int const * n, double const * r, double* f, double* u, double const * ax, double const * ay, double const * az)
{
gagafetip4p(n, r, u, ax, ay, az);
}
This way the linker may use either gagafetip4p
or gagafetip4p_ depending on the naming
convention used by the compilers.
Fortran is case insensitive while C is case sensitive. Fortran compiler
converts function names into lower case at compilation. So the
functions in C must be lower case. Again you use nm
to check the link names.
When you use a compiler to link a program, the standard library is
automatically added. For example, if we are linking a program written
in C++, we can write: g++ -o program file1.o file2.o
We do not need add the standard library as it is automatically added:
g++ -o program file1.o file2.o -lstdc++ When linking a
program written C and Fortran, the standard library of at least one
them must be explicitly added. For example, when I link a program
compiled with g++ and g77
. I write something like: g++ -o program file1cpp.o
file2cpp.o file1fort.o file2fort.o -lg2c When I link
program compiled with g++ and xlf. I write something like:
g++ -o program file1cpp.o file2cpp.o file1fort.o file2fort.o
-L/opt/ibmcmp/xlf/8.1/lib -lxlf90 -lxlfmath -lxl
It is also possible from C common blocks defined in Fortran. For
example, we have the following common block defined in Fortran:
integer n
real*8 array(3)
common /block/ n, array
In C the common block is declared as a structure.
struct Block {
int n;
double array[3];
} block_;
The names of Block, n
and array do not matter, but the members must
have the same order as in the common block and same sizes. The variable
name block_ do matter as it is used to link
the object. It follows the same rules as functions' names and therefore
has the same issues (Matching Function Names,
Case).
Again, command nm is helpful check link
names.
Generated
on Wed Aug 15 13:28:06 2007 for Lanczos Saddle Point Searches
by
1.5.2
home