************************************************** J3/02-230r1 To: J3 From: Aleksandar Donev Reviewed by J3 Interop Subgroup at 162 Date: August 13 2002 Subject: Enhanced C_LOC: Noninteroperable Arguments Reference: Paper J3/02-229r1 ************************************************** Summary ______________________________________ We propose a modification of the specification of C_LOC from ISO_C_BINDING to allow nonpolymorphic scalar targets of any (interoperable or not) nonparameterized derived type as an argument. The modification will significantly enhance C_LOC's functionality by allowing limited (opaque) interoperability of any Fortran object with C. The associated (required) enhancement to C_F_POINTER is also proposed. ______________________________________ Rationale ______________________________________ A Fortran program needs to provide the following data to a C library in an opaque way because that library will call a Fortran routine that uses this data to do something (in this case perform a matrix-vector product): TYPE :: My_Data TYPE(Matrix(KIND=C_DOUBLE,SIZE=:)), POINTER :: A=>NULL() REAL(KIND=C_DOUBLE), DIMENSION(:), ALLOCATABLE :: x, y END TYPE My_Data TYPE(My_Data), TARGET :: Fortran_data Using the proposed extension, this can be done by simply making a C pointer handle to the object Fortran_data: TYPE(C_PTR) :: C_handle C_handle=C_LOC(Fortran_data) ______________________________________ Edits: ______________________________________ ___________________ 382:17-25 Replace with: C_LOC(X) Description: Returns the C address of the argument or the target associated with the argument. Class: Inquiry function Argument: X shall (1) be (a) a procedure that is interoperable, or (b) a procedure pointer associated with an interoperable procedure, (2) have interoperable type and type parameters and be (a) a variable that has the TARGET attribute and is interoperable, (b) an allocated allocatable variable that has the TARGET attribute, or (c) an associated scalar pointer, or (3) be a nonpolymorphic scalar of a nonparameterized derived type and be (a) a nonallocatable variable that has the TARGET attribute, or (b) an allocated allocatable variable that has the TARGET attribute. Result: The result is determined as if a pointer assignment px=>X were made, where px is a pointer with global scope. If X is interoperable or has interoperable type and type parameters, then the result is the value that the C processor returns as the result of applying the unary "&" operator (as defined in the C standard, 6.5.3.2.) to the target of px. The result is a value that can be used as an actual CPTR argument in a call to C_F_POINTER where FPTR is of the same type and type parameters as X. Such a call to C_F_POINTER shall pointer assign FPTR to px. NOTE: When the actual argument is a scalar of noninteroperable derived type, the result of C_LOC provides an opaque ``handle'' for it. In an actual implementation, this handle may be the C ``base'' address of the argument; However, portable C functions should treat it as a void (generic) C pointer that cannot be dereferenced (6.5.3.2 in the C standard). ___________________ ___________________ 383:14-16+1 Replace with: C_F_POINTER(CPTR, FPTR [, SHAPE]) Description: Associates a pointer with the target of a C pointer and specifies its shape. Class: Subroutine Arguments: CPTR shall be a scalar of type C_PTR. It is an INTENT(IN) argument. (Case I) The value of CPTR is the C address of an entity that is interoperable with variables of the type and type parameters of FPTR and is not a Fortran variable that does not have the TARGET attribute. (Case II) The value of CPTR is the result of C_LOC with an argument of the same noninteroperable type as FPTR that shall not been deallocated or have become undefined due to execution of a RETURN or END statement since the reference to C_LOC. FPTR shall be a pointer. It is an INTENT(OUT) argument. (Case I) FPTR has interoperable type and type parameters. It becomes pointer associated with the target of CPTR. If it is an array, its shape is specified by SHAPE. (Case II) FPTR is of a noninteroperable type. It becomes pointer associated with the actual argument passed to C_LOC to obtain the value of CPTR. ___________________ ___________________ 471:22+ Add: C.10.2.3 Example of reverse communication between C and Fortran. The following example demonstrates how a Fortran processor can make a modern OO random number generator written in Fortran available to a C program: USE ISO_C_BINDING ! Assume this code is inside one scoping unit TYPE, EXTENSIBLE :: Random_Stream ! A (uniform) random number-generator (URNG) CONTAINS PROCEDURE(RandomUniform), PASS(stream) :: Next=>NULL() ! Generates the next number from the stream END TYPE Random_Stream INTERFACE ! Abstract interface of Fortran URNG FUNCTION RandomUniform(stream) RESULT(number) CLASS(Random_Stream), INTENT(INOUT) :: stream REAL(C_DOUBLE) :: number END FUNCTION END INTERFACE A polymorphic object of base type Random_Stream is not interoperable with C. However, we can make such a random-number generator available to C by packaging it inside another nonpolymorphic, nonparametrized container derived type: TYPE :: URNG_State ! No BIND(C) as not interoperable CLASS(Random_Stream), POINTER :: stream=>NULL() CHARACTER(LEN=10) :: method="LC" ! The algorithm to be used--to be set by the C program END TYPE URNG_State The following two procedures will enable a companion program to use our Fortran URNG: ! Initialize a uniform random number generator SUBROUTINE InitializeURNG(state_handle), BIND(C) TYPE(C_PTR), INTENT(IN), VALUE :: state_handle ! An opaque handle for the URGN TYPE(URNG_State), POINTER :: state ! A ''real'' handle for the URNG CALL C_F_POINTER(C_PTR=state_handle, F_PTR=state) ! Convert the opaque handle into a usable pointer ... ! Allocate state%stream with a dynamic type depending on state%method ... END SUBROUTINE InitializeURNG ! Generate a random number: FUNCTION GenerateUniform(state_handle) RESULT(number), BIND(C) TYPE(C_PTR), INTENT(IN), VALUE :: state_handle REAL(C_DOUBLE) :: number TYPE(URNG_State), POINTER :: state CALL C_F_POINTER(C_PTR=state_handle, F_PTR=state) number=state%stream%Next() ! Use the type-bound function Next to actually generate the number END FUNCTION GenerateUniform ___________________