Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28497 Discussions

Fortran TYPE with Pointers and ALLOCATABLE arrays question

fbalderasintel
1,554 Views
Ihave constructed an interface between a C struct and a Fortran TYPE which works for all but a struct which contains an array. The other members of the struct/Type pass OK but not the array.

The C allocates the space for the variable size array, assigns values, and passes it via a pointer. The Fortran TYPE with pointer receives the memory space OK (no crash) but the values are garbage. I do the ALLOCATE to TARGET array and assign the Pointer to the TARGET but I'm not certain where the memoryis supposed to get"mapped" to the targetarray.

I am using VS2008 x64 for both with IVF 11.1.
I researched the Forum, the IVF mixed language document and the Fortran 2003 book and
having run out of ideas, I'm seeking some advice.

I am attaching a file "C_to_Fortran.txt" which shows the C struct, allocation and assignment,the C calling subroutine, the FORTRAN "TYPE"and receivingsubroutine as well as a print out of the results. Thanks in Advance for any help.

0 Kudos
15 Replies
netphilou31
New Contributor II
1,553 Views
Hi,

I think that if the array is already allocated in the C code, then it is not necessary to declare it as pointer in the Fortran type declaration code. Moveover when you reassing it to the TraceData array which is allocated in the Fortran code, the orignal memory blok which contains the values stored in the C code is no more available in the Fortran code. Another think is that you probalby need to use the BIND("C") declaration when declaring your subroutine interface.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,553 Views
In FORTRAN

real, DIMENSION(:), POINTER :: TraceDataArray

points to an array descriptor that maps out the array. It does NOT point to the 1st element of an allocated array (what C/C++ uses).

In your Fortran type use
...
integer(C_PTR) :: cp_TraceDataArray
...

in subroutine use

real, DIMENSION(:), POINTER :: TraceDataArray ! local pointer
...
call C_F_POINTER(SeismicLine%cp_TraceDataArray, TraceDataArray, [SeismicLine%numTraces*SeismicLine%numSamples])


The allocate was performed on the C/C++ side, the array pointer interpretation is performed on the FORTRAN side

Jim Dempsey
0 Kudos
fbalderasintel
1,553 Views

Thanks JIm, I am trying your suggestion,

I included "use ISO_C_BINDING" trying to resolve (C_PTR) and C_F_POINTER..

But I get thse errors:

The first 2 occur where (C_PTR) is declared as in:

integer (C_PTR) :: cp_TraceDataArray

Message 1 remark #5082: Directive ignored - Syntax error, found '(' when expecting one of: :: , : ] C:\agr_dev\Ver1.0\K3F_Utils\K3F_Utils.f90 398


I also triedC_PTRwithout parens

Error 2 error #6683: A kind type parameter must be a compile-time constant. [C_PTR] C:\agr_dev\Ver1.0\K3F_Utils\K3F_Utils.f90 26

The 3rd one :

Error 3 error #6285: There is no matching specific subroutine for this generic subroutine call. [C_F_POINTER] C:\agr_dev\Ver1.0\K3F_Utils\K3F_Utils.f90 454

occurs at

call c_f_pointer(SeismicLine%cp_TraceDataArray, TraceDataArray, [SeismicLine%numTraces*SeismicLine%numSamples])

Is there a specific LIB that I am missing for C_PTR and C_F_POINTER ? Or Propery setting?

0 Kudos
IanH
Honored Contributor II
1,553 Views
[bash]TYPE(C_PTR) :: your_variable_name[/bash]
0 Kudos
fbalderasintel
1,553 Views
Yes, that works.

What about C_F_POINTER, I tried to declare that as well, but couldn't.
0 Kudos
IanH
Honored Contributor II
1,553 Views
I had assumed error 3 was just a consequence of the erroneous declaration of the C_PTR component.

The only "declaration" required is the USE ISO_C_BINDING statement.

Check that the first argument to C_F_POINTER is a C_PTR, the second argument is a fortran POINTER with rank "n", and the third argument is an integer array with "n" elements.
0 Kudos
fbalderasintel
1,553 Views

I am now able to compile C_F_Pointer, thanks, but I'm not quite there yet


When I use the TYPE (C_PTR) as follows I get Error 1 below.

TYPE :: SeismicLineStruct
sequence
integer
:: numTraces
integer
:: numSamples
TYPE
(C_PTR) :: cp_TraceDataArray
END TYPE SeismicLineStruct



Error1 error #6027: All derived type fields within a sequenced type must be of a derived-type that is sequenced (R424.2). [CP_TRACEDATAARRAY]C:\agr_dev\Ver1.0\K3F_Utils\K3F_Utils.f9021

- - - - - - - - -
So I tried a different approach in the meantime where I
tried "flattening" thestructure, taking theC_PTR line out of the struct and passing all as separate arguements. This compiles and runs w/o crash but the resulting array values are undefined.

subroutine FProcessSeisLineC ( numTraces, numSamples , TraceDataPtr)

!DEC$ ATTRIBUTES DLLEXPORT, ALIAS: 'FProcessSeisLineC' ::FProcessSeisLineC
!DEC$ ATTRIBUTES integer,reference ::numTraces
!DEC$ ATTRIBUTES integer, reference::numSamples

integer(4), intent(IN) :: numTraces !THESE COME THROUGH OK
integer(4), intent(IN) :: numSamples !THESE COME THROUGH OK

TYPE (C_PTR) ,intent(IN) :: TraceDataPtr ! local pointer

real, DIMENSION(:), POINTER :: TraceData ! local pointer

character(LEN=80) Path, errmsg,src !

integer(1) lDim

lDim = numTraces * numSamples; ! Calc size needed
call c_f_pointer( TraceDataPtr, TraceData, [lDim]) ! I TAKEIT THAT THE ALLOCATE IS DONE IN HERE
- - - - - - - - - - - - - - -
I could still use some help to understand why the structure above is complaining about a "sequence type". I
would rather usethe structurethan the flattened approach. Even the flattened approach doesnt quite know how to find the address of the float array malloc'd in C.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,553 Views
IMHO there is a bug in iso_c_binding.f90 (Intelmodule file)

The type should include SEQUENCE in the event that a C_PTR is used within a SEQUENCED user type.

! -------------------------------------------------------------------------

! C_PTR, C_FUNPTR, C_NULL_PTR, C_NULL_FUNPTR

! -------------------------------------------------------------------------

TYPE, BIND(C) :: C_PTR

SEQUENCE !**** addsequence here ***
PRIVATE
INTEGER(C_INTPTR_T) :: ptr

END TYPE C_PTR

Wouldn't hurt to do the same for C_FUNPTR

>>call c_f_pointer( TraceDataPtr, TraceData, [lDim]) ! I TAKEIT THAT THE ALLOCATE IS DONE IN HERE

No, the allocation was performed by your C/C++ code.
c_f_pointer is constructing an array descriptor (FORTRAN array pointer).

A FORTRAN array descriptor contains something along the line of:
status
rank
C type pointer to block of memory
lowIndex, highIndex, stride (1st rank)
lowIndes, highIndes, stride (2nd rank)
...

Think of this as a C/C++ object that maps allocated memory (e.g. CSTRING)

Jim Dempsey

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,553 Views
IMHO there is a bug in iso_c_binding.f90 (Intelmodule file)

The type should include SEQUENCE in the event that a C_PTR is used within a SEQUENCED user type.


I don't think so. BIND(C) states that the TYPE is interoperable (same order and alignment) with "companion C processor". SEQUENCE states that the TYPE is interoperable with other Fortran structures (via sequence association). The two are incompatible, in general case, and user should pick one or another. The type should have BIND(C) attribute, not SEQUENCE.

I don't like SEQUENCE, by the way.

0 Kudos
Steven_L_Intel1
Employee
1,553 Views
Jugoslav is correct: BIND(C) implies even stricter requirements than SEQUENCE, and C_PTR has BIND(C). One cannot use both attributes together.
0 Kudos
JVanB
Valued Contributor II
1,553 Views
If you insist on a SEQUENCE type rather than converting to bind(C), change
TYPE (C_PTR) :: cp_TraceDataArray
to
integer(C_INTPTR_T) :: addr_TraceDataArray
Then you can either interpret it as a Cray pointer or use TRANSFER to convert it to TYPE(C_PTR).
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,553 Views
Steve,

I disagree

The OP had a user defined type, of SEQUENCE type, containing a "user defined type" of type C_PTR .AND. type C_PTR is .NOT. a SEQUENCE type. Meaning user could not include member variable of type(C_PTR) (of type .NOT. of sequence type) in his SEQUENCE type type. (requiring additional coding hoops to jump through to use the pointer)

type(C_PTR) is effectively compatible with SEQUENCE type (just as INTEGER or REAL types are compatible with SEQUENCE types, and thus permitted within and enclosing type of sequence type).

Unfortunately, IVF did not determine that the type(C_PTR) only contained a single member variable of type INTEGER(C_INTPTR_T) and thus was compatible with sequence type. IOW no padding or alignment issues.

Inserting SEQUENCE into TYPE(C_PTR) would be benign to existing (working) code, and make a TYPE(C_PTR) permissible in a user defined type of sequence type. So I do not think there is a downside to this.

Your comments would be appreciated.

Jim Dempsey
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,553 Views
That would work too, but would (may) require additional hoop jumping (TRANSFER to C_PTR then callC_F_POINTER to convert to array pointer).

Jim
0 Kudos
Steven_L_Intel1
Employee
1,553 Views
Jim,

The standard says that if a type is BIND(C), then it must not be SEQUENCE. SEQUENCE prevents reordering of components but does not guarantee a layout interoperable with the "companion C processor". The standard also says that C_PTR is BIND(C). I think initially we did not define it as such, but it is now.

Yes, that means you can't use C_PTR in a SEQUENCE type. I would argue that SEQUENCE is an obsolete feature and should generally be replaced with BIND(C) in most cases. You can put variables of interoperable derived type in a COMMON, but not in EQUIVALENCE.

We're not going to extend the language in this area. If you are retrofitting existing code, C_PTR may not be the right choice for an address.
0 Kudos
IanH
Honored Contributor II
1,553 Views
Here's a modified version of your original attachment showing how I'd approach this. There are important changes on the C side as well as the fortran side.

C_to_Fortran.txt
0 Kudos
Reply