- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This topic must have been beaten to death, but the issue I've encountered seems very odd.
Here is the C code:
void test_array(int *, int *, double **); // To test accessing a Fortran 2D array.
void test_get_array()
{
int i;
int narr1, narr2;
double *farr;
test_array(&narr1, &narr2, &farr);
for (i=0;i<narr1*narr2; i++)
printf("%d %f\n",i,farr[i]);
}
and the Fortran:
subroutine test_array(narr1, narr2, cptr) bind(C)
!DEC$ ATTRIBUTES DLLEXPORT :: test_array
use, intrinsic :: iso_c_binding
integer(c_int) :: narr1, narr2
TYPE (C_PTR) :: cptr
real(c_double), allocatable, target :: a(:,:)
integer :: i1, i2
integer :: n1=4, n2=3
allocate(a(n1,n2))
do i1 = 1,n1
do i2 = 1,n2
a(i1,i2) = i1 + 10*i2
enddo
enddo
narr1 = n1
narr2 = n2
cptr = c_loc(a)
write(*,'(4f6.0)') a
end subroutine
This is the output:
11. 12. 13. 14.
21. 22. 23. 24.
31. 32. 33. 34.
0 0.000000
1 12.000000
2 13.000000
3 14.000000
4 21.000000
5 22.000000
6 23.000000
7 24.000000
8 31.000000
9 32.000000
10 33.000000
11 34.000000
What has happened to the first array entry?
Hang on! I just remembered seeing something about SAVE. When I add that to the declaration of a(:) I get the first entry correctly. I'm guessing that not SAVEing immediately clobbers the start of the array somehow on subroutine return. I decided to leave the post here because the phenomenon is interesting and I'd like to see comments on it.
Thanks
Gib
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Not putting SAVE on a local ALLOCATABLE array causes it to be automatically deallocated on routine end. None of the storage is defined anymore.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks Steve, it makes sense now. It was just a matter of chance that the rest of the array entries were still there.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Gib,
From a functional point of what your code was trying to do, using SAVE is not necessarily the correct action. The correct action would be to declare the array a as pointer. This way the allocated object is not auto de-allocated upon return (same as SAVE), however, your C code is free to call the routine to obtain an additional object. If your code is only interested in allocating and manipulating a single object then use SAVE. But then as written, there is no way to later reclaim the memory by way of DEALLOCATE. Note, while use of pointer will provide for persistent allocatable objects you cannot use the Fortran pointer to an array as a C pointer to the blob of data. You'd still use the cptr = c_loc(a), but then this would lose the address of the Fortran array descriptor, which would be necessary for the deallocation. For this, your C interface should add a void* as an additional argument that receives the address of the array descriptor. The Fortran routine would then need to be coded to return the reference to the pointer to the array.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Jim,
When I was originally flailing around trying to find out how to do this, getting confused by some misleading online information, one variation I tried used an allocatable array - this is the example I posted. I realised immediately after posting that it works fine with a static array (with SAVE). In my actual usage, the array will be global, and SAVEd automatically, and deallocation will not be an issue. Thanks for explaining pointer vs. allocatable.
Gib
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
jimdempseyatthecove wrote:
...Note, while use of pointer will provide for persistent allocatable objects you cannot use the Fortran pointer to an array as a C pointer to the blob of data. You'd still use the cptr = c_loc(a), but then this would lose the address of the Fortran array descriptor, which would be necessary for the deallocation. For this, your C interface should add a void* as an additional argument that receives the address of the array descriptor. The Fortran routine would then need to be coded to return the reference to the pointer to the array.
If the underlying Fortran object is a pointer target (perhaps one created by allocating a Fortran pointer), and the address of that underlying object is then passed through to C, there is no need to worry about the descriptor (which is inaccessible to a standard conforming program anyway) - the C address of the underlying object and its shape, if it is an array, is all that is required if that object needs to be deallocated at some later stage.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page