Opaque pointer sharing between C and Fortran

Opaque pointer sharing between C and Fortran

Hello,

I am trying to connect some C code to some Fortran code without rewriting large portions of either. The fortran code has several derived type definitions which are apparently NOT interoperable with C struct definitions (the derived types contain fortran pointer components). Changing the derived type defintions is NOT a particularly attractive option for us at this point so I was hoping to be able to treat the derived type allocations as opaque memory pointer handles in C and rely on fortran routines alone to manipulate the fortran data structures.

Anyhow, I am trying to get my head wrapped around the differences between a C pointer and a Fortran pointer. Reading up on the ISO_C_BINDING info I thought I understood that the C_LOC function will return the 'C' compatible address of a fortran data structure given some limitations on the fortran data types being used. With that in mind, the following fortran code is supposed to allocate some memory for a fortran derived data type called 'SomeDerivedType' and return the 'C' compatible address of that memory back to the calling C function:

function makeDerivedType() bind (c, name='makeDerivedType')
   use iso_c_binding
   type (C_PTR) :: makeDerivedType
   type (SomeDerivedType), pointer :: sdt
   allocate(sdt)
   makeDerivedType = C_LOC(sdt)
end subroutine

When I invoke this function I get a segfault during the call to C_LOC(sdt) instead.

I must be misunderstanding what C_LOC does. I assumed it would just return an opaque C pointer to the memory used by the fortran allocated data structure so that I could pass that pointer back and forth between the C and Fortran code at will so long as the Fortran code did all the internal manipulation of the data.

Anyone able to shed some light on my misunderstanding? It would be greatly appreciated.

-Travis

6 帖子 / 0 全新
最新文章
如需更全面地了解编译器优化,请参阅优化注意事项

I don't think your example explains well enough what you're trying to do.  I doubt that you really want to see a C_PTR to an unassociated Fortran pointer.  I'm surprised that you don't get complaints about trying to allocate something not declared as allocatable.  Once you have allocated a data region (which has to be declared with TARGET attribute, although ifort probably doesn't enforce it), you can use C_LOC to make a C_PTR to it.

If you return a pointer to a derived type containing Fortran pointers, there will be no portable way to make use of those pointers in C.  You would have to write C code to interpret the descriptor as it is used internal to ifort.

Thank you TimP for your reply.  It is quite possible that I am just not fluent enough with fortran to explain what I think that code fragment is doing. My intention was to somehow return a valid C pointer to the area of memory set aside by the fortran 'allocate(sdt)' statement. I thought that allocate would automatically 'associate' the 'sdt' fortran pointer with the allocated memory without needing an explicit target?

At any rate, a large amount of our logic is written in Python and/or C and so having an opaque pointer to carry around in the C code allows us to do the higher level logic there and still pass the opaque pointer back and forth to the fortran routines when we need to manipulate the DerivedType data.

In case it clarifies my intentions here is another fragment of fortran code which I was hoping to use to inspect the data structure pointed to by the opaque handle:

subroutine examineDerivedType(this) bind (c, name='examineDerivedType')
   use iso_c_binding
   type (C_PTR), value :: this
   type (SomeDerivedType), pointer :: that
   call C_F_POINTER(this, that)
   write (*,*) "examineSomeDerivedType_ that%someInteger", that%someInteger
end subroutine

so If this were all working correctly I would expect to be able to use it from C as follows:

[c]

extern void makeSomeDerivedType();
extern void examineSomeDerivedType(void* m);
int main( int argc, const char* argv[] )
{
      void* m = makeSomeDerivedType();
      examineDerivedType_(m);
}

[/c]

Just a follow up in case anybody else is interested. I still haven't figured out how to create a fortran function that returns a C_PTR to fortran allocated memory but I was able to do it via a fortran subroutine as follows:

!Given the address of a C_PTR this subroutine allocates the memory required
!for a SomeDerivedType derived data type, initializes it with the given values,
!and stores the C_LOCated address in the C_PTR.
subroutine makeDerivedType_(cdt) bind (c, name='makeDerivedType_')
   use iso_c_binding
   type (C_PTR) :: cdt
   type (SomeDerivedType), pointer :: fdt
   allocate(fdt)    
   fdt%someInteger=4 
   cdt = C_LOC(fdt)
end subroutine  

A corresponding fortran access routine would be something like:

!This subroutine converts the given C_PTR value to a fortran pointer making
!it accessible again from Fortran
subroutine examineDerivedType_(this) bind (c, name='examineDerivedType_')
   use iso_c_binding
   type (C_PTR), value :: this
   type (SomeDerivedType), pointer :: that
   call C_F_POINTER(this, that)
   write (*,*) "that%someInteger", that%someInteger
end subroutine

And finally, an example of using it from C:

extern void makeDerivedType_(void* m);
extern void examineDerivedType_(void* m);
int main( int argc, const char* argv[] )
{
      void* m = 0;
      makeDerivedType_(&m);
      examineDerivedType_(m);
}

Which compiler version are you using?  I have some notes that indicate that ifort has had issues returning C_PTR's from functions in the 12.0 era.  (I don't have access to recent compilers on linux to see what the situation is today.)  Your code examples for the function in the OP look ok to me, bar what I presume are transcription errors. In the subroutine makeDerivedType argument case I'd be inclined to declare the argument as void** on the C side.

Hi Ian,

Yes, I am using ifort version 12.0.2 so maybe it is just a compiler glitch.  At any rate I am just relieved that the two languages can share pointers even if opaquely. It helps in my case to be able to delegate functionality to the most appropriate language in our mixed language system.

Also, thanks for the void** pointer :)

-Travis

发表评论

登录添加评论。还不是成员?立即加入