Reputation: 10165
I have tried to modify code from this this question to ISO_C_BINDING, but C_F_POINTER call results in Undefined pointer/array (VS2010 debugger) and print*, f_arr(i)
triggers segmentation fault. I think I do follow closely instructions from the array interop.
extern void subr(int, float*);
int main(int argc, char **argv){
int N = 3;
int i;
float data[3];
for (i=0;i<N;i++) data[i]=i;
subr(N,data);
}
subroutine subr(n, c_arr) BIND(C)
USE, INTRINSIC :: ISO_C_BINDING
implicit none
INTEGER(C_INT),VALUE :: n
TYPE (C_PTR) :: c_arr
REAL(C_FLOAT), POINTER :: f_arr (:)
integer :: i,ml,mu
CALL C_F_POINTER (c_arr, f_arr, (/n/) )
ml = lbound(f_arr,1)
mu = ubound(f_arr,1)
do i=ml,mu
print*, f_arr(i)
enddo
end subroutine
Do you know why I get failure in pointer conversion? (intel fortran compiler)
Upvotes: 2
Views: 2234
Reputation: 29126
The example for calling Fortran from C via the ISO_C_BINDING
in the Intel documentation is not very clear. But elsewhere, I have found this explanation: TYPE (C_PTR) :: X
is equivalent to C's void **
, i.e. pointer to void pointer. We need void *
, a void pointer, and therefore must declare C_ARR
with the VALUE
attribute:
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
But I'm not sure that you need to call C_F_POINTER
at all. The following works, too:
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
(Maybe it is good practice to use C_F_POINTER
, I don't know. That's something the Intel documentation should show: When it is needed and when not.)
Edit: After looking a bit more into the interface in the Intel example, I think the C_F_POINTER
call is needed there, because the array is part of a C struct
. When declaring your TYPE
, you cannot make the members arrays of a variable length, so you have to declare the data member as TYPE (C_PTR)
and go through the C_F_POINTER
routine.
So here is the same example for passing a pointer to a structure cleaned up:
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
This is called from C thus:
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;
}
You can also pass the structure by value if you give OBJ
the VALUE
attribute.
Upvotes: 4