6.1.5 Работа с указателями C
Указатели C представляются в Fortran с помощью специального неявного производного типа type(c_ptr) (с закрытыми компонентами). Указатели C отличаются от объектов Fortran с атрибутом POINTER. Таким образом, для преобразования из указателей C или в указатели C необходимо использовать процедур intrinsic преобразования. Для некоторых приложений использование предполагаемого типа (TYPE(*)) может быть альтернативой указателю C, а также можно использовать библиотечные процедуры для доступа к указателям Fortran из C. См. Дополнительную взаимосвязанность Fortran и C.
Вот пример использования указателей C в Fortran:
use iso_c_binding
type(c_ptr) :: cptr1, cptr2
integer, target :: array(7), scalar
integer, pointer :: pa(:), ps
cptr1 = c_loc(array(1)) ! The programmer needs to ensure that the
! array is contiguous if required by the C
! procedure
cptr2 = c_loc(scalar)
call c_f_pointer(cptr2, ps)
call c_f_pointer(cptr2, pa, shape=[7])
При преобразовании массивов C в Fortran необходимо передать одномерный SHAPE аргумент.
Если указатель является аргументом процедуры с поддержкой межъязыковой работы, то, как правило, он должен быть объявлен с использованием атрибута VALUE. void* соответствует TYPE(C_PTR), VALUE, а TYPE(C_PTR) соответствует void**.
Указатели процедур обрабатываются аналогично указателям; тип C — TYPE(C_FUNPTR), а процедуры intrinsic преобразования — C_F_PROCPOINTER и C_FUNLOC.
Рассмотрим два примера передачи указателя на процедуру из C в Fortran и обратно. Обратите внимание, что эти примеры также очень похожи на передачу обычных указателей между этими языками. Сначала рассмотрим этот код на C:
/* Procedure implemented in Fortran. */
void get_values (void (*)(double));
/* Call-back routine we want called from Fortran. */
void
print_it (double x)
{
printf ("Number is %f.\n", x);
}
/* Call Fortran routine and pass call-back to it. */
void
foobar ()
{
get_values (&print_it);
}
Соответствующая реализация для get_values на Fortran, которая правильно получает указатель на процедуру из C и может вызвать её, приведена в следующем MODULE:
MODULE m
IMPLICIT NONE
! Define interface of call-back routine.
ABSTRACT INTERFACE
SUBROUTINE callback (x)
USE, INTRINSIC :: ISO_C_BINDING
REAL(KIND=C_DOUBLE), INTENT(IN), VALUE :: x
END SUBROUTINE callback
END INTERFACE
CONTAINS
! Define C-bound procedure.
SUBROUTINE get_values (cproc) BIND(C)
USE, INTRINSIC :: ISO_C_BINDING
TYPE(C_FUNPTR), INTENT(IN), VALUE :: cproc
PROCEDURE(callback), POINTER :: proc
! Convert C to Fortran procedure pointer.
CALL C_F_PROCPOINTER (cproc, proc)
! Call it.
CALL proc (1.0_C_DOUBLE)
CALL proc (-42.0_C_DOUBLE)
CALL proc (18.12_C_DOUBLE)
END SUBROUTINE get_values
END MODULE m
Далее, мы хотим вызвать функцию C, которая ожидает аргумент-указатель на процедуру, и передать ей процедуру Fortran (которая, очевидно, должна быть совместимой с C!). Опять же, функция C может быть:
int
call_it (int (*func)(int), int arg)
{
return func (arg);
}
Её можно использовать в следующем коде Fortran:
MODULE m
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
! Define interface of C function.
INTERFACE
INTEGER(KIND=C_INT) FUNCTION call_it (func, arg) BIND(C)
USE, INTRINSIC :: ISO_C_BINDING
TYPE(C_FUNPTR), INTENT(IN), VALUE :: func
INTEGER(KIND=C_INT), INTENT(IN), VALUE :: arg
END FUNCTION call_it
END INTERFACE
CONTAINS
! Define procedure passed to C function.
! It must be interoperable!
INTEGER(KIND=C_INT) FUNCTION double_it (arg) BIND(C)
INTEGER(KIND=C_INT), INTENT(IN), VALUE :: arg
double_it = arg + arg
END FUNCTION double_it
! Call C function.
SUBROUTINE foobar ()
TYPE(C_FUNPTR) :: cproc
INTEGER(KIND=C_INT) :: i
! Get C procedure pointer.
cproc = C_FUNLOC (double_it)
! Use it.
DO i = 1_C_INT, 10_C_INT
PRINT *, call_it (cproc, i)
END DO
END SUBROUTINE foobar
END MODULE m
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-13.3.0/gfortran/Working-with-C-Pointers.html