I am writing a small C++ program which passes a 2-D array (of complex numbers) to a Fortran subroutine and receives it back filled with values. I wrote a version which passe
Multidimensional arrays in Fortran are stored as flat column-major arrays in memory. They are not pointers to pointers—they're really just 1D arrays where you have to do some extra arithmetic to compute array indices.
The correct way to pass the array from C++ is like this:
extern "C" void carray_(struct cpx *A);
...
struct cpx A[2*2];
carray_(A);
complex<double> P[2][2];
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
// note order of indicies: A is column-major
P[i][j] = std::complex<double>(A[j*2 + i].r, A[j*2 + i].i);
}
}
The way to do this in this era is to use the ISO C Binding. Officially this is part of Fortran 2003, but is is widely supported by Fortran compilers, including gfortran. It even includes interoperability of complex types! See the list of types in the gfortran manual under the chapter "Intrinsic Modules", section "ISO_C_Binding". Plus there are several examples in the chapter "Mixed-Language Programming". On the C++ side, use extern C for the routine to be called in order to use C calling conventions without name-mangling. On the Fortran side, use the ISO C Binding. Then you will have compatibility at the language level rather than having to make assumptions about how the compilers work.
A two-dimensional array in c++ is not--I repeat not--the same as a pointer to a pointer{*}!
When you do
struct cpx** A;
you are setting up to construct a so called "ragged array" for which there is not a fortran equivalent. You want something like
struct cpx *A[2][2] = new struct cpx[2][2];
which is a pointer to a two-dimensional array with rows 2 long.
{*} Yes, you can access a pointer-to-pointer structure using the two-dimensional array notation, but they are laid out differently in memory. ::grumble:: People who tell other people that arrays and pointers are the same thing in c need to meet the Big Foam Clue Bat.
<row-dimension>*<column-dimension>*sizeof(<type>)
. It's name decays to a pointer-to-type.<column-dimension<*sizeof(<type>*)
and the other are <row-dimension>*sizeof(<type>)
.The thing to be aware of here is that c++ and fortran believe arrays are stored differently in memory.
C++ thinks that the memory position after a[1][1]
is a[1][2]
, while fortran believes that is is a[2][1]
. The distinction is between row-major (c, c++, etc) and column major (fortran, matlab, a few others).
Note that this is separate from fortran indexing arrays from 1 by default.