passing an array to an extern C for fortran routine

F

foice

Hello everyobdy
I managed to use the extern C trick to use my fortran routine :)
unfortunately
I am able to pass only plain double, float and integers, not array or
vectors.

If I pass a vector or an array everything compiles but the numbers
that are undestood as input in the fortran are actually meaningless
(7.823e-231 and similar things)

There must be some evil in the passing of the arguments that are not
plain scalars.

I declared the routine as

extern "C" {

void vxxxxx_(vector<double>&, double&, int&, int&, complex<
double>*);
}

the fortran has
subroutine vxxxxx(p,vmass,nhel,nsv , vc)
double precision p(0:3)

but then the components of p print out silly numbers ...

Do you have idea how to pass a vector or an array?

All the best
Roberto
 
J

James Kanze

I managed to use the extern C trick to use my fortran routine
:) unfortunately I am able to pass only plain double, float
and integers, not array or vectors.
If I pass a vector or an array everything compiles but the
numbers that are undestood as input in the fortran are
actually meaningless (7.823e-231 and similar things)
There must be some evil in the passing of the arguments that
are not plain scalars.

Yes and no.
I declared the routine as
extern "C" {
void vxxxxx_(vector<double>&, double&, int&, int&, complex<
double>*);
}
the fortran has
subroutine vxxxxx(p,vmass,nhel,nsv , vc)
double precision p(0:3)
but then the components of p print out silly numbers ...
Do you have idea how to pass a vector or an array?

The official response would be to use `extern "Fortran"', and
read the documentation as to how this extension maps Fortran
types to C++. A response which might be of some good would be
to read the documentation of your Fortran compiler, to see how
they map their arguments to the C ABI of the system. But in any
case: you almost certainly can't pass a vector, and you might
have problems with two dimensional arrays, even taking into
account that C uses row major ordering, and Fortran column
major.

For single dimensional arrays, there's a good change that it
will work straight off. For single dimensional vector, you
might try &v[0], and declare the extern as taking a double*, or
whatever.
 
V

Victor Bazarov

I managed to use the extern C trick to use my fortran routine :)
unfortunately
I am able to pass only plain double, float and integers, not array or
vectors.

If I pass a vector or an array everything compiles but the numbers
that are undestood as input in the fortran are actually meaningless
(7.823e-231 and similar things)

There must be some evil in the passing of the arguments that are not
plain scalars.

I declared the routine as

extern "C" {

void vxxxxx_(vector<double>&, double&, int&, int&, complex<
double>*);
}

the fortran has
subroutine vxxxxx(p,vmass,nhel,nsv , vc)
double precision p(0:3)

but then the components of p print out silly numbers ...

As they should. The vector is not a simple sequence of elements, it's
an object that contains data members, and a pointer to a dynamic array
is usually one of them.
Do you have idea how to pass a vector or an array?

Most likely there is no way to pass a vector straight up *if* the other
side (Fortran) does not have an equivalent type. What you usually do is
pass the address of the first element of the vector, and on the Fortran
side use the array, like you have:

extern "C" {
void vxxxxx_(double*, ....
}

subroutine vxxxxx(p, ...
double precision p(0:3)

As for the array of 'complex<double>', it might be even trickier. You
should consider decomposing it into the array of the real parts and the
array of the imaginary parts, and passing them separately. Or, maybe
there is a way to declare a two-dimensional array on the Fortran side,
but you need to experiment to see what members you get where.

extern "C" {
void vccccc_(complex<double>*);
}

subroutine vccccc(cplx)
double precision cplx(0:100,1:2)
c cplx(x,1) = real part
c cplx(x,2) = imaginary part

maybe... Or maybe the indices are swapped and you should say

subroutine vccccc(cplx)
double precision cplx(1:2, 0:100)
c cplx(1,x) = real part
c cplx(2,x) = imaginary part

Now, those things aren't really defined in C++. You're in the
compiler-specific territory. No warranties attached.

V
 
F

foice

Thank you so much for your replies.
In the end I decomposed the vector and passed each component as a
separate double. This stinks but works and seems really solid and
portable.
Thanks again for all the explanations.
Roberto
 
J

James Kanze

On 10/13/2010 12:35 PM, foice wrote:

[...]
As for the array of 'complex<double>', it might be even trickier. You
should consider decomposing it into the array of the real parts and the
array of the imaginary parts, and passing them separately. Or, maybe
there is a way to declare a two-dimensional array on the Fortran side,
but you need to experiment to see what members you get where.

FWIW: Fortran requires that complex be represented as an array
of two REAL or two DOUBLE, with the real part first, and the
imaginary part second. All known implementations of
complex<float> and complex<double> do, in fact, meet this
requirement, and there was a proposal at one time to make it
mandatory, precisely for reasons of compatibility with Fortran.
(Which is a bit tricky, since it imposes layout on a non-POD
type. But the idea was that it would be up to the
implementation to make it work.) I don't know what happened
with the proposal, but you're probably "pretty safe" using
arrays (or passing the address of the first element of a vector)
of complex<float> for COMPLEX in Fortran.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top