I'm trying to create a c_ptr to an allocated class(*),pointer variable, and then convert it back later into a Fortran pointer. Here is a toy example:
program test use iso_c_binding implicit none type :: blah integer :: i = 0 end type blah class(*),pointer :: p,q type(c_ptr) :: cp allocate(p,source=blah(999)) cp = c_loc(p) allocate(blah :: q) ! (*) either of these !allocate(q,mold=blah()) ! call c_f_pointer(cp,q) select type (q) ! works as long as (*) is present, otherwise crash type is (blah) write(*,*) 'q%i:',q%i end select end program test
If I don't have the allocate(blah :: q), the c_f_pointer call seems to works, but then it crashes when I try to access anything in the variable. So, my question is: is this the right way to do this? My concern is that it's a memory leak (it seems like the memory grabbed in this allocation would be lost when I call c_f_pointer? But I'm not sure). I'm using ifort 17.0.2.
This will never work. When you do C_LOC, you lose ALL of the extra info that is kept with a polymorphic entity, and there is no way to reconstruct it. At best you could convert back to a pointer of fixed type.
Ideally, the compiler would complain about the use of a polymorphic pointer in the call to C_F_POINTER, but the current implementation doesn't allow for that and the standard doesn't require a check.
So, this would be good?:
program test2 use iso_c_binding implicit none type :: blah integer :: i = 0 end type blah class(*),pointer :: p type(c_ptr) :: cp type(blah),pointer :: q allocate(p,source=blah(999)) cp = c_loc(p) call c_f_pointer(cp,q) write(*,*) 'q%i:',q%i end program test2
It seems to run fine.
Can C_LOC be applied to a polymorphic variable? My understanding had been "no", but looking at the standard just now, I'm not so sure. If it isn't allowed, you can wrap the pointer in a type, and apply c_loc to a variable of that type. I've used this trick before.
Neil Carlson wrote:
Can C_LOC be applied to a polymorphic variable? My understanding had been "no", but looking at the standard just now, I'm not so sure. ..
The standard revision that is "in the works" i.e., N2118 toward Fortran 2015 which, by the way, strives to include via TS 29113 further (some read this as enhanced) interoperability with C, explains on the dummy argument X in the C_LOC(X) function,
It shall either be a variable with interoperable type and kind type parameters, or be a nonpolymorphic variable with no length type parameters.
I infer that to mean X can be a polymorphic variable whose dynamic instance is an interoperable type with interoperable kind type parameters; otherwise, X will have to be a nonpolymorphic variable with no length type parameters.
So in the example above from Message #3, if the type of blah were to be interoperable (which it is not, at least in principle), then the C_LOC(p) instruction will be standard-conforming. That is my quick take on it.
What you inferred is exactly what led me to have doubts, but it is an inference and not clearly right (to me at least), though I hope it is.
Boxing the polymorphic pointer has the advantage of preserving the extra metadata that one loses when applying c_loc directly to the pointer. For example
program main use iso_c_binding type box class(*), pointer :: p => null() end type type(box), target :: pbox type(box), pointer :: qbox type(c_ptr) :: cp allocate(pbox%p, source=1) cp = c_loc(pbox) call c_f_pointer(cp, qbox) select type (q => qbox%p) type is (integer) print *, 'got integer', q class default print *, 'lost dynamic type' end select end program
The "box" method also works for me (it also has the advantage of also working on gfortran, which the other two do not). So, the theory is that this is OK because box is a nonpolymorphic variable with no length type parameters (even though it does contain a polymorphic variable?)
FortranFan's "inference" is exactly what the standard intends to say - the argummt shall either be interoperable (which clss(*) is not) or s non-polymorphic variable. Non-standard. As I said, it would be nice if ifort complained about this. I have little doubt that some other compilers do.