Пример вызова Fortran из C через ISO_C_BINDING
в документации Intel не очень ясен. Но в другом месте я нашел это объяснение: TYPE (C_PTR) :: X
эквивалентно void **
C, т.е. указатель на пустой указатель. Нам нужен void *
, пустой указатель, и поэтому мы должны объявить C_ARR
с атрибутом VALUE
:
SUBROUTINE SUBR(N, C_ARR) BIND(C)
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
INTEGER (C_INT), VALUE :: N
TYPE (C_PTR), VALUE :: C_ARR
REAL (C_FLOAT), POINTER :: F_ARR(:)
CALL C_F_POINTER(C_ARR, F_ARR, (/N/))
PRINT *, F_ARR
END SUBROUTINE
Но я не уверен, что вам вообще нужно звонить C_F_POINTER
. Также работает следующее:
SUBROUTINE SUBR(N, ARR) BIND(C)
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
INTEGER (C_INT), VALUE :: N
REAL (C_FLOAT) :: ARR(N)
PRINT *, ARR
END SUBROUTINE
(Возможно, использование C_F_POINTER
является хорошей практикой, я не знаю. Документация Intel должна показывать это: когда это необходимо, а когда нет.)
Редактировать: после более подробного изучения интерфейса в примере с Intel, я думаю, что здесь необходим вызов C_F_POINTER
, потому что массив является частью C struct
. При объявлении вашего TYPE
вы не можете создавать массивы элементов переменной длины, поэтому вам нужно объявить элемент данных как TYPE (C_PTR)
и пройти процедуру C_F_POINTER
.
Итак, вот тот же пример передачи указателя на очищенную структуру:
SUBROUTINE SUBR_STRUCT(OBJ) BIND(C)
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
TYPE, BIND(C) :: VECTOR
INTEGER (C_INT) :: LEN
TYPE (C_PTR) :: DATA
END TYPE VECTOR
TYPE (VECTOR), INTENT(IN) :: OBJ
REAL (C_FLOAT), POINTER :: ARR(:)
CALL C_F_POINTER (OBJ%DATA, ARR, (/OBJ%LEN/))
PRINT *, ARR
END SUBROUTINE
Это вызывается из C таким образом:
struct obj
{
int len;
float *data;
};
extern void subr_struct(const struct obj *);
int main(int argc, char **argv)
{
float data[] = {0.12, 0.15, 0.18, 0.23, 0.29};
struct obj o = {5, data};
subr_struct(&o);
return 0;
}
Вы также можете передать структуру по значению, если вы дадите OBJ
атрибут VALUE
.
person
M Oehm
schedule
28.01.2014