cpointersfortranfortran-iso-c-binding

Check for ISO_C_BINDING usage in Fortran calling C function


I've asked a few questions on ISO_C_BINDING, and I made a routine. Since I've always made quite a few mistakes dealing with Fortran POINTER, I want to make it sure that there is no mistake or some weird point that is not a recommended way.

(Fortran part)

program test
  use iso_c_binding
  implicit none
  interface
    subroutine get_value_array(in, num) bind(C, name='get_value_Array')
      use iso_c_binding
      implicit none
      type(C_PTR),           intent(inout)  :: in
      integer(C_INT), value, intent(in)     :: num
    end subroutine
  end interface

  real(C_DOUBLE), allocatable, target  :: array(:)
  real(C_DOUBLE),              pointer :: array_fptr(:)
  type(C_PTR)                          :: array_cptr

  integer :: array_len

  allocate(array(12))
  array_len = size(array,1)

  array_cptr = C_LOC(array)

  call get_value_array (array_cptr, array_len)

  call C_F_POINTER(array_cptr, array_fptr, [array_len])

  print *, 'array_fptr'
  print *, array_fptr

  print *, 'array'
  print *, array

end program

(C part)

void get_value_Array(double **in, int num) {
  int i;
  for (i = 0; i < num; i++) {
    (*in)[i] = i+1;
  } 
} 

(Output)

 array_fptr
   1.00000000000000        2.00000000000000        3.00000000000000
   4.00000000000000        5.00000000000000        6.00000000000000
   7.00000000000000        8.00000000000000        9.00000000000000
   10.0000000000000        11.0000000000000        12.0000000000000
 array
   1.00000000000000        2.00000000000000        3.00000000000000 
   4.00000000000000        5.00000000000000        6.00000000000000 
   7.00000000000000        8.00000000000000        9.00000000000000 
   10.0000000000000        11.0000000000000        12.0000000000000 

To make it sure, the process is

  1. array_cptr is associated to array with C_LOC function. (Maybe 'associate' is not a proper terminology here since it's Fortran pointer related terminology. What should I call it?)
  2. array gets modified when I call get_value_array, since the subroutine(or C function) modifies where the array_cptr points to.
  3. array_fptr is associated to array through array_cptr when I call C_F_POINTER

And finally array_cptr and array_fptr are different object(?) to each other, while pointing at the same target array, right?


Solution

  • The statements in the question are ambiguous. To be precise.

    1. With the Fortran statement array_cptr = C_LOC(array), array_cptr is assigned the C address of array.

    2. When get_value_array is invoked, the value of array is ultimately modified by the C function. The Fortran code also makes allowance for the subroutine (or C function) to modify the C address stored in array_cptr - the dummy argument is declared as INTENT(INOUT) and does not have the VALUE attribute, and consistent with that the C function takes the pointer to the array by reference (i.e. the C formal parameter is declared as a pointer to pointer to double). But the C function does not make such modifications to the C address stored in array_cptr. For the code shown, there is an unnecessary level of indirection.

    3. The Fortran code associates array_fptr with the thing referenced by the C address in array_cptr. Because the C address in array_cptr has not been been changed by the C function, array_fptr continues to be associated with array. Execution of C_F_POINTER in this case does not change the state of the program.

    array_cptr is a different thing to array_fptr - but they have the same target (array_cptr is an object, array_fptr is associated with an object - pointers in Fortran are not objects in their own right, unlike in C).