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

Fortran C++ Mixed Code Problem

sick
Beginner
1,440 Views

I'd like to return a 2d array from a fortran subroutine to the calling c++ function.

My current fortran test:

SUBROUTINE ANALYSE (FILE, RESULTS, NUMRESULTS)

!DEC$ ATTRIBUTES C, REFERENCE :: ANALYSE

INTEGER :: NUMRESULTS

INTEGER, pointer :: RESULTS(:,:)

CHARACTER*256 FILE

INTEGER ALLOC_ERR

NUMRESULTS = 3

ALLOCATE (RESULTS(NUMRESULTS,2),STAT = ALLOC_ERR)

RESULTS(1,1) = 0

RESULTS(1,2) = 1

RESULTS(2,1) =2

RESULTS(2,2) =3

RESULTS(3,1) =4

RESULTS(3,2) =5

END

and the c++ counterpart:

extern "C" void analyse (char* FILE, int** RESULTS, int * NUMRESULTS);

void TestClass::Testfunction()

{

int** res= new (int*);

int numres;

analyse(strFilename.ToAscii(), res,numres);

DoSomethingWithTheResults(res,numres);

}

The problem is that the dereferencing of the res pointer in fortran results in heap problems.

What is the right way to do it ?

Thanks in advance,

Stefan

0 Kudos
1 Solution
Jugoslav_Dujic
Valued Contributor II
1,440 Views
F2003 C interoperability features are the cleanest path. Untested sample:

subroutine ANALYSE (pResults, dim1, dim2) bind(C)

use ISO_C_BINDING

type(C_PTR):: pResults !interoperable with void**
integer(C_INT):: dim1, dim2

integer, allocatable:: MyMat(:,:)
dim1 = 42
dim2 = 26
!Note the reverse order of dimensions between C and Fortran
allocate(MyMat(dim2,dim1))
MyMat(:,:) = 999
pResults = C_LOC(MyMat)

end subroutine ANALYSE
=============================================
extern "C" void ANALYSE(int** p, int& dim1, int& dim2)
...
int** p;
int dim1, dim2;
ANALYSE(p, dim1, dim2);
for (int i=0; i for (int j=0; j //Not sure if I got this right, but you get the point:
printf("%4d", *(p + i*dim2 + j));



View solution in original post

0 Kudos
9 Replies
Steven_L_Intel1
Employee
1,440 Views
A Fortran deferred-shape array is not compatible with a C pointer. If you pass the bounds, you can use an adjustable array (M,N).
0 Kudos
sick
Beginner
1,440 Views
Can you give me a short example based on my dummy code ?
I'm quite new to fortran and the only thing i could find out about the adjustable arrays are that they seems like pointer
to a given array with the length (M,N). But which kind of datatype should i define in the c interface? int**, int* ?
And is it possible to use allocate on this type DIMENSION ?
A Fortran deferred-shape array is not compatible with a C pointer. If you pass the bounds, you can use an adjustable array (M,N).

0 Kudos
TimP
Honored Contributor III
1,440 Views
The adjustable (terminology from prior to 1990) array corresponds to a single level pointer on the C side. The C code has to calculate the position of array elements, as is easily done, since the syntax requires the Fortran leading dimension to appear as an argument. More examples than you want are available on the web. For example, an excerpt from f2c translation of the Levine-Callahan-Dongarra vectors benchmark:
for (j = 2; j <= i__2; ++j) {
int i__3 = j - 1;
for (int i__ = 1; i__ <= i__3; ++i__)
aa[i__ + j * aa_dim1] = aa[j + i__ * aa_dim1] + bb[i__ + j *
bb_dim1];
}
There is no Fortran correspondence to C ** definition (array of pointers), unless, as Jugoslav shows, you declare an explicit C_PTR array.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,441 Views
F2003 C interoperability features are the cleanest path. Untested sample:

subroutine ANALYSE (pResults, dim1, dim2) bind(C)

use ISO_C_BINDING

type(C_PTR):: pResults !interoperable with void**
integer(C_INT):: dim1, dim2

integer, allocatable:: MyMat(:,:)
dim1 = 42
dim2 = 26
!Note the reverse order of dimensions between C and Fortran
allocate(MyMat(dim2,dim1))
MyMat(:,:) = 999
pResults = C_LOC(MyMat)

end subroutine ANALYSE
=============================================
extern "C" void ANALYSE(int** p, int& dim1, int& dim2)
...
int** p;
int dim1, dim2;
ANALYSE(p, dim1, dim2);
for (int i=0; i for (int j=0; j //Not sure if I got this right, but you get the point:
printf("%4d", *(p + i*dim2 + j));



0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,440 Views
Quoting - tim18
There is no Fortran correspondence to C ** definition (array of pointers).

There is no correspondence in its general case (array of pointers), but you can interoperate with a function argument of type something** or something*&, which essentially represents a pointer [to a 1-D array] passed by reference, as in my sample above.
0 Kudos
TimP
Honored Contributor III
1,440 Views
Quoting - Jugoslav Dujic
F2003 C interoperability features are the cleanest path. Untested sample:


integer, allocatable:: MyMat(:,:)
dim1 = 42
dim2 = 26
!Note the reverse order of dimensions between C and Fortran
allocate(MyMat(dim2,dim1))
MyMat(:,:) = 999
pResults = C_LOC(MyMat)

It looks as if this should fail on a strict Fortran compiler, until MyMat is given TARGET attribute.
0 Kudos
sick
Beginner
1,440 Views
Thank you Jugoslav ! That is exactly what i was looking for.
I wonder if this is possible with f90, too. I found no examples about it...
Quoting - Jugoslav Dujic
F2003 C interoperability features are the cleanest path. Untested sample:

subroutine ANALYSE (pResults, dim1, dim2) bind(C)

use ISO_C_BINDING

type(C_PTR):: pResults !interoperable with void**
integer(C_INT):: dim1, dim2

integer, allocatable:: MyMat(:,:)
dim1 = 42
dim2 = 26
!Note the reverse order of dimensions between C and Fortran
allocate(MyMat(dim2,dim1))
MyMat(:,:) = 999
pResults = C_LOC(MyMat)

end subroutine ANALYSE
=============================================
extern "C" void ANALYSE(int** p, int& dim1, int& dim2)
...
int** p;
int dim1, dim2;
ANALYSE(p, dim1, dim2);
for (int i=0; i for (int j=0; j //Not sure if I got this right, but you get the point:
printf("%4d", *(p + i*dim2 + j));




0 Kudos
jimdempseyatthecove
Honored Contributor III
1,440 Views

>>integer, allocatable:: MyMat(:,:)

Depending on version allocatable gets auto deallocated when descriptor goes out of scope. Consider using pointer

integer, pointer:: MyMat(:,:)


Jim Dempsey
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,440 Views

>>integer, allocatable:: MyMat(:,:)

Depending on version allocatable gets auto deallocated when descriptor goes out of scope. Consider using pointer

integer, pointer:: MyMat(:,:)



Yes, my bad; at least ALLOCATABLE, SAVE:: for MyMat is required. However, either way (pointer or allocatable), there's no good way to release the memory later (as I wrote the code), because "casting" to a C_PTR (p**) kills all the information needed for successful deallocation.

To overcome the problem, either MyMat should be made persistent (put in a MODULE or COMMON) [which hampers parallelization or code reuse for multi-tasking], or a more complex scheme devised.

To the original poster:
1) If you need the matrix one-off, without the need to deallocate it later, the code above will do, with POINTER or ALLOCATABLE, SAVE added
2) Without ISO_C_BINDING, it is still doable, but you have to rely on Integer (Cray) pointers, which are clumsier and less portable than ISO_C_BINDING. If you use a recent compiler, you'd be better off with the standard solution.
0 Kudos
Reply