Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
29300 Discussions

Passing dynamically allocated variable between fortran and C

v8hadas
Beginner
533 Views
Hi There,

I have an ifort 9.1 and a g++ 4.3.2 running on my OpenSuSE 11.1 box. I pass a few variables between Fortran and C++ where the unusual thing is that the Fortran code is the still maintained and the C++ code is the legacy. It means that Fortran calls C++ and not backwards.

All goes well for simple variables and even for arrays until I try to pass a dynamic array (defined as allocatable and allocated runtime). The values I get there are really weird, have nothing to do what was there before. On the other hand I am a C++ guy (doing fortran for three days) so I might miss something obvious.

What works fine:

type type1
real*4, dimension(5:10) :: val1
real*4, dimension(10:20) :: val2
end type
type(type1) test1


What does not work (passes weird values):

type type2
real*4, allocatable, dimension(:,:) :: val1
real*4, dimension(:,:) :: val2
end type
type(type2) test2
! ...
allocate(test2%val1(5,10)) ! stat check is not done
allocate(test2%val2(10,20)) ! stat check is not done


So when I do the following calls:

call callcpp(test1)
call callcpp(test2)


Then the first call passes the proper values to C++ and the second call passes seemingly a bit of junk. I tried with integers instead of reals to see if something is just mixed up with reals but that does not look like the case - values are messy for integer arrays too.

The C(++) call is defined as:

extern "C" {
void callcpp_(char *pStruct);
}

void callcpp_(char *pStruct) {
int Pointer1 = 0, Pointer2 = 0;
for (int j = 0; j < 100; j++) { // 100 is just for test
printf("%d TestIntStruct[%d] == %d\n", Pointer1, j, *((int*)(pStruct + Pointer1)));
printf("%d TestIntStruct[%d] == %#12.6g\n", Pointer2, j, *((int*)(pStruct + Pointer2)));
Pointer1 += sizeof(int);
Pointer2 += sizeof(float);
}
}


So... that is the problem. Static allocation looks to pass proper values, dynamic passes wrong ones even if those look to be the same when printed from the Fortran code to the screen.

Cheers,
Sandor
0 Kudos
2 Replies
TimP
Honored Contributor III
533 Views
As you chose not to use a compiler which supports "type, bind(c) :: type2" it seems like bets are off.
I don't see that you followed the textbook suggestions about how an allocatable array might be used in C, which include passing the array by argument association and depending on the compiler to employ copy-in copy-out.
0 Kudos
Steven_L_Intel1
Employee
533 Views
Fortran allocatable arrays are not the same as C pointers. When you have a derived type component as an allocalatble (or pointer) array, what is actually in the structure is a "descriptor" with much more than just a pointer. The layout of this is described in the Fortran documentation.

If you were using Fortrtan 10.0 or later, you could use the Fortran 2003 interoperability features to make the components of type C_PTR and then use Fortran POINTER arrays, allocating the array and then using C_LOC to convert the Fortran pointer to a C pointer.

Otherwise, you can make the structure element an INTEGER(INT_PTR_KIND()), create POINTER arrays (not ALLOCATABLE) in the function, allocate them and use LOC to get the address.
0 Kudos
Reply