- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Is it possible (with or without Fortran 2003 ISO_C_BINDING) to dynamically allocate an output array in a fortran subroutine and pass it back to a C++ program as shown below? Using Intel Fortran v11.059 for Mac OS X 10.5.7, I get a segmentation fault on the allocate statement using the compiler settings as shown below.
icpc -g -traceback -c driver.cpp
ifort -check -g -traceback -nofor-main -lstdc++ test.f driver.o
c Return a dynamically allocated array from Fortran back to C++
subroutine foo(nmax, in, out)
integer nmax
real in(nmax)
real, dimension(:), pointer :: out
integer ierr
allocate(out(nmax), stat=ierr)
print *,'allocate returned: ',ierr
do i=1,nmax
out(i) = in(i) * i
print *,i,in(i),out(i)
end do
return
end subroutine foo
#include
extern "C" void foo_(int* nmax, float* in, float* out);
// Test dynamically allocated fortran output array from C++
int main()
{
int nmax = 10;
float* in = new float[nmax];
float* out = NULL;
for (int i = 0; i < nmax; i++)
in = (i + 1) * 10.0;
foo_(&nmax, in, out);
std::cout << "Done!" << std::endl;
delete[] in;
delete[] out;
return 0;
} // end main
icpc -g -traceback -c driver.cpp
ifort -check -g -traceback -nofor-main -lstdc++ test.f driver.o
c Return a dynamically allocated array from Fortran back to C++
subroutine foo(nmax, in, out)
integer nmax
real in(nmax)
real, dimension(:), pointer :: out
integer ierr
allocate(out(nmax), stat=ierr)
print *,'allocate returned: ',ierr
do i=1,nmax
out(i) = in(i) * i
print *,i,in(i),out(i)
end do
return
end subroutine foo
#include
extern "C" void foo_(int* nmax, float* in, float* out);
// Test dynamically allocated fortran output array from C++
int main()
{
int nmax = 10;
float* in = new float[nmax];
float* out = NULL;
for (int i = 0; i < nmax; i++)
in = (i + 1) * 10.0;
foo_(&nmax, in, out);
std::cout << "Done!" << std::endl;
delete[] in;
delete[] out;
return 0;
} // end main
Link Copied
8 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
A C pointer is not the same as a Fortran assumed-shape array, and if you allocate the data in Fortran it must be deallocated in Fortran.
The Fortran code could look something like this:
[plain]subroutine foo(nmax, in, outp) use, intrinsic :: iso_c_binding integer nmax real in(nmax) type(C_PTR) :: outp real, dimension(:), pointer :: out integer ierr allocate(out(nmax), stat=ierr) print *,'allocate returned: ',ierr do i=1,nmax out(i) = in(i) * i print *,i,in(i),out(i) end do outp = C_LOC(out) return end subroutine foo[/plain]
On the C++ side, you need to make sure that you pass the address of a pointer to the Fortran code, so that Fortran can store the allocation address into the pointer. Note that one should use POINTER and not ALLOCATABLE here - the POINTER won't get automatically deallocated on exit.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - Steve Lionel (Intel)
On the C++ side, you need to make sure that you pass the address of a pointer to the Fortran code, so that Fortran can store the allocation address into the pointer.
Just so there is no confusion, let me say this another way. What you pass from the C++ side needs to be float**, not float* (e.g., &out rather than just out). Alternatively, you could make foo a function that returns a pointer and assign it to out on the C++ side.
Two other minor cautions:
1. You are assuming that a Fortran procedure named FOO will appear to have the name foo_ to C (and thus appear to be a C external named foo_ to C++). This is the most common implementation decision, but it is not universally true, and indeed it isn't even always true for ifort. You might want to use a BIND(C,NAME='...') clause to force the Fortran procedure to have a particular C name.
2. Theoretically, storage allocated to a Fortran POINTER could be discontiguous. (Fortran POINTERs are capable of pointing to discontiguous arrays, and there is no requirement in the Fortran standard that storage allocated to a POINTER be contiguous.) If any Fortran implementation actually did that, this whole scheme would fall apart. I know of no existing compiler that does this, nor do I know of any possible reason why a compiler might find it desirable to do so, but that doesn't mean there will never be such a reason. Its all a question of how paranoid you want to be about future changes in the computing environment. One possible alternative would be to replace the ALLOCATE statement with a reference to malloc (using C interoperability), thus concpetually allocating the storage in C and making it contiguous. As an added benefit, storage allocated this way could be deallocated using free, either from Fortran or from the C++ side.
-Kurt
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If you just ALLOCATE a pointer array, it will be contiguous. You're right that a POINTER can get assigned a non-contiguous array slice, but you have to go out of your way to do that. The Fortran 2003 C interoperability features provide all you need to do this right.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm loving Fortran 2003's ISO_C_BINDING more & more. However, the customer currently insists on using ifort v9. [My previous post you mentioned this new feature requires ifort v10.1 or greater.] We're happy with Intel Fortran 11 & think everyone should upgrade! :-)
I was able to get my little example working using non standard Cray Pointers (circa Fortran 1978?). Using float** for the C++ as discussed in this post. I thought I was going to be headed for a long three day weekend when the compiler said it didn't like my converting F90 pointers to cray pointers inside the module level interface block?!?
Back to google looking for related posts, I see a previous discussion here at Intel regarding CVF_1D_DESCRIPTOR so that C can use the F90 pointers but can't find the definition of the data type struct for it and CVF_2D_DESCRIPTOR?
It looks like I could leave the F90 program as-is & teach the C++ driver how to use the pointers vs convert the Fortran and it's interface block from F90 pointers to Cray pointers while waiting for everyone to get on the ISO_C_BINDING band wagon so I can conver the whole thing once and for all? [Plan B is to update ftoc for F90 to C++.] Thanks!
I was able to get my little example working using non standard Cray Pointers (circa Fortran 1978?). Using float** for the C++ as discussed in this post. I thought I was going to be headed for a long three day weekend when the compiler said it didn't like my converting F90 pointers to cray pointers inside the module level interface block?!?
Back to google looking for related posts, I see a previous discussion here at Intel regarding CVF_1D_DESCRIPTOR so that C can use the F90 pointers but can't find the definition of the data type struct for it and CVF_2D_DESCRIPTOR?
It looks like I could leave the F90 program as-is & teach the C++ driver how to use the pointers vs convert the Fortran and it's interface block from F90 pointers to Cray pointers while waiting for everyone to get on the ISO_C_BINDING band wagon so I can conver the whole thing once and for all? [Plan B is to update ftoc for F90 to C++.] Thanks!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Forget playing with descriptors. It can be done but it's not worth the hassle. Also, CVF used a different layout than Intel Fortran does. (It is documented in the "Building Applications" section of the manuals.)
You can do it with Cray pointers. Something like this:
You can do it with Cray pointers. Something like this:
[plain]subroutine foo(nmax, in, outp)
integer nmax
real in(nmax)
real, dimension(*) :: out
pointer (outp, out)
integer ierr
outp = malloc(nmax*4)
do i=1,nmax
out(i) = in(i) * i
print *,i,in(i),out(i)
end do
return
end subroutine foo[/plain]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the warning about trying to teach C++ F90 pointers. I found the page in the documentation under Mixed Language Support, Array Descriptors. That would have been a huge frustrating waste of time especially since as you note Compaq & Intel have different internals for the pointers!
Thanks for the tip on the interface block with Cray pointers. I found the page in the documentation right after the above page under Integer Pointers. The example includes the interface block. Basically, the interface block calls the pointer an integer then the pointer and pointee are declared in the code. Thanks!
Note in the above example in the documentation, the C code does not pass the address of the pointer as we'd discussed above just int* p not &p; the example works so I'll press on converting the program. I'll put in a requirement to get everyone upgraded to the latest Intel Fortran that supports the Fortran 2003 ISO_C_BINDING way of doing things. Thanks!
Thanks for the tip on the interface block with Cray pointers. I found the page in the documentation right after the above page under Integer Pointers. The example includes the interface block. Basically, the interface block calls the pointer an integer then the pointer and pointee are declared in the code. Thanks!
Note in the above example in the documentation, the C code does not pass the address of the pointer as we'd discussed above just int* p not &p; the example works so I'll press on converting the program. I'll put in a requirement to get everyone upgraded to the latest Intel Fortran that supports the Fortran 2003 ISO_C_BINDING way of doing things. Thanks!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
As mentioned in Fortran books and also in this thread,
Fortran pointers and C pointers aren't compatible per
se. For instance, Fortran pointers can point to
non-contiguous memory when they are used to slice a
multi-dimensional buffer. The question I have is as
follows: Assuming that the Fortran pointer is only
used to dynamically allocate an array of integer, real,
or double precision type (i.e. the pointer always
points to contiguous memory where simple intrinsic
types are stored), will the following code work:
main.f90:
program pointertest
integer*8 :: iattr
real, dimension(:), pointer :: data
integer :: n
n = 100
allocate(data(n))
! fill buffer etc
iattr = loc(data(1))
print *,'F: ',iattr
call my_c_function(data,n)
deallocate(data)
end program
my_c_function.c:
#include
void my_c_function_(float *data, int *n) {
printf("C: %lldn",(long long)data);
/* do something with data buffer */
return;
}
This example seems to work fine (i.e. data can be properly
accessed without problems in the C world) and provides a
consistent output. Is it just luck or will it always be the
case as long as the assumptions (see above) are met? In
other words, will this code always pass the correct address
(where the data starts) to C?
The new ISO_C_BINDING would certainly allow to handle this
situation in a somewhat cleaner way, I know.
Where is the additional information that belongs to a
Fortran pointer (stride information, length information, etc)
actually stored? A Fortran pointer doesn't seem to behave
like a structure/class...
Fortran pointers and C pointers aren't compatible per
se. For instance, Fortran pointers can point to
non-contiguous memory when they are used to slice a
multi-dimensional buffer. The question I have is as
follows: Assuming that the Fortran pointer is only
used to dynamically allocate an array of integer, real,
or double precision type (i.e. the pointer always
points to contiguous memory where simple intrinsic
types are stored), will the following code work:
main.f90:
program pointertest
integer*8 :: iattr
real, dimension(:), pointer :: data
integer :: n
n = 100
allocate(data(n))
! fill buffer etc
iattr = loc(data(1))
print *,'F: ',iattr
call my_c_function(data,n)
deallocate(data)
end program
my_c_function.c:
#include
void my_c_function_(float *data, int *n) {
printf("C: %lldn",(long long)data);
/* do something with data buffer */
return;
}
This example seems to work fine (i.e. data can be properly
accessed without problems in the C world) and provides a
consistent output. Is it just luck or will it always be the
case as long as the assumptions (see above) are met? In
other words, will this code always pass the correct address
(where the data starts) to C?
The new ISO_C_BINDING would certainly allow to handle this
situation in a somewhat cleaner way, I know.
Where is the additional information that belongs to a
Fortran pointer (stride information, length information, etc)
actually stored? A Fortran pointer doesn't seem to behave
like a structure/class...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
A Fortran pointer to an array is, internally, the address of a data structure whose layout is described in the mixed-language programming section of the documentation. There is no straightforward way of seeing this from Fortran without "cheating".

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