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
초급자
1,496 조회수

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 포인트
1 솔루션
Jugoslav_Dujic
소중한 기여자 II
1,496 조회수
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 포인트
9 응답
Steven_L_Intel1
1,496 조회수
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 포인트
sick
초급자
1,496 조회수
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 포인트
TimP
명예로운 기여자 III
1,496 조회수
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 포인트
Jugoslav_Dujic
소중한 기여자 II
1,497 조회수
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 포인트
Jugoslav_Dujic
소중한 기여자 II
1,496 조회수
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 포인트
TimP
명예로운 기여자 III
1,496 조회수
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 포인트
sick
초급자
1,496 조회수
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 포인트
jimdempseyatthecove
명예로운 기여자 III
1,496 조회수

>>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 포인트
Jugoslav_Dujic
소중한 기여자 II
1,496 조회수

>>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 포인트
응답