Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29004 Discussions

how to pass 2d array from C to Fortran?

coolweather1
Beginner
1,660 Views

I need to pass 2d arrays from C to Fortran using interoperability features.

in C :
arrays are declared as

int ** ia;
float ** fa;
double **da;

int m, n;    // dimensions [m x n]

allocation is done as :

ia = (int **)malloc(sizeof(int *) * m);
for(i=0; i!=m; ++i) ia = (int *) malloc(sizeof(int) * n);
.... 

// call fortran subroutine
fortran_call(ia, fa, da);

in FORTRAN:

subroutine fortran_call(ia, fa, da, m, n) bind(c)

use iso_c_binding

integer(c_int), intent(in)  :: ia(n,m)
real(c_float), intent(in)  :: fa(n,m) 
real(c_double), intent(in)  :: da(n,m) 

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!  the arrays are not passed to Fortran subroutine correctly !!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

end subroutine 

Could you explain me please how to pass 2d arrays (in form : iso_c_type **) to FORTRAN, please ?

Thank you so much !

0 Kudos
3 Replies
jimdempseyatthecove
Honored Contributor III
1,660 Views
One way is to change your C allocation: ia = (int **)malloc(sizeof(int *) * m); iaBlob = (int*)malloc(sizeof(int) * m * n; for(i=0; i!=m; ++i) ia = &iaBlob[i*n]; Then pass the location of iaBlob (FORTRAN reference to iaBlob), together with m and n. SUBROUTINE FOO(ia, m, n) integer :: m, n integer :: ia(n, m) ! or ia(0:n-1,0:m-1) (note index swap) Your current code would require you to pass an array of pointers (some more work on FORTRAN side) Jim Dempsey
0 Kudos
IanH
Honored Contributor III
1,660 Views
coolweather wrote:

I need to pass 2d arrays from C to Fortran using interoperability features.

in C :
arrays are declared as

[cpp] int ** ia; float ** fa; double **da; int m, n;    // dimensions [m x n] // allocation is done as : ia = (int **)malloc(sizeof(int *) * m); for(i=0; i!=m; ++i) ia = (int *) malloc(sizeof(int) * n); // ....  // call fortran subroutine fortran_call(ia, fa, da); [/cpp]
No prototype for fortran_call shown. This call has three arguments. ia here is an array of pointers to arrays of int. This allows what is known as a "ragged array" - ia[0] could point to an array of size 1, ia[2] could point to an array of size 100. (Note "could" - you've not done that, but the capability is there). The storage for the array pointed at by ia[0] and the storage for the array pointed at by ia[1] will probably not be adjacent in memory - they are separate "malloc's".

in FORTRAN:

[fortran]subroutine fortran_call(ia, fa, da, m, n) bind(c) [/fortran]
Five arguments. No declarations for m and n shown.
[fortran] use iso_c_binding integer(c_int), intent(in)  :: ia(n,m) [/fortran]
ia here is a rectangular array (all rows must be the same length). In memory the data for the array is stored as a contiguous sequence. From a C point of view, this is equivalent to a single malloc, with the programmer then managing the concepts of rows and columns "ia[ix * ny + iy]". In terms of the matching C procedure the argument would be a "int *" (or equivalently an int[]). This is not consistent with the nature of the array and argument on the C side.
[fortran] real(c_float), intent(in) :: fa(n,m) real(c_double), intent(in) :: da(n,m) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!  the arrays are not passed to Fortran subroutine correctly !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! end subroutine [/fortran]

Could you explain me please how to pass 2d arrays (in form : iso_c_type **) to FORTRAN, please ?

Thank you so much !

Do you want a ragged array, or a rectangular array?
0 Kudos
TimP
Honored Contributor III
1,660 Views
A Fortran CONTIGUOUS 2D array is interoperable with a C array using only a single level of pointers, with explicit calculation of the address offset (e.g. the way it's done by the legacy f2c translator). As Jim said, you would need to handle each row individually if you use a ** in C. The lack of direct equivalence appears to be the reason why there isn't specific provision in iso_c_binding. It looks like expanding on this subject might keep me busy a few months if I write a post-retirement book (no, I haven't committed to take the retirement offer yet).
0 Kudos
Reply