C_FUNLOC
function from the intrinsic module ISO_C_BINDING
accepts a non-interoperable procedure argument.
The C_FUNPTR
value produced should not be converted to a C function pointer, but may be converted to a suitable (also non-interoperable) Fortran procedure pointer with the C_F_PROCPOINTER
subroutine from ISO_C_BINDING
.
For example,
USE ISO_C_BINDING ABSTRACT INTERFACE SUBROUTINE my_callback_interface(arg) CLASS(*) arg END SUBROUTINE END INTERFACE TYPE,BIND(C) :: mycallback TYPE(C_FUNPTR) :: callback END TYPE ... TYPE(mycallback) cb PROCEDURE(my_callback_interface),EXTERNAL :: sub cb%callback = C_FUNLOC(sub) ... PROCEDURE(my_callback_interface),POINTER :: pp CALL C_F_PROCPOINTER(cb%callback,pp) CALL pp(...)
This functionality may be useful in a mixed-language program when the C_FUNPTR value is being stored in a data structure that is manipulated by C code.
C_LOC
function from the intrinsic module ISO_C_BINDING
accepts an array of non-interoperable type,
and the C_F_POINTER
function accepts an array pointer of non-interoperable type.
The array must still be non-polymorphic and contiguous.
This improves interoperability with mixed-language C and Fortran programming, by letting the program pass an opaque “handle” for a non-interoperable array through a C routine or C data structure, and reconstruct the Fortran array pointer later. This kind of usage was previously only possible for scalars.
C_PTRDIFF_T
has been added to the intrinsic module ISO_C_BINDING
.
This is the integer kind that corresponds to the C type ptrdiff_t
, which is an integer
large enough to hold the difference between two pointers.
For example, the interface
Interface Function diff_cptr(a,b) Bind(C) Use Iso_C_Binding Type(C_ptr),Value :: a, b Integer(C_ptrdiff_t) diff_cptr End Function End Interfaceinteroperates with the C function
ptrdiff_t diff_cptr(void *a,void *b) { return a - b; }
ISO_C_BINDING
, the procedures C_LOC
and C_FUNLOC
are
considered to be pure procedures, and C_F_POINTER
and C_F_PROCPOINTER
are considered
to be impure.
When it is used within a pure procedure, the argument of C_FUNLOC
must also
be a pure procedure.
BIND(C)
routine,
even those with the ALLOCATABLE
or POINTER
attribute.
An assumed-rank argument is passed by reference as a “C descriptor”; it is then up to
the C routine to decode what that means.
The C descriptor, along with several utility functions for manipulating it,
is defined by the source file ISO_Fortran_binding.h
; this can be found
in the compiler's library directory (on Linux this is usually /usr/local/lib/NAG_Fortran
,
but that can be changed at installation time).
This topic is highly complex, and beyond the scope of this document. The reader should direct their attention to the Fortran 2018 standard, or to a good textbook.
TYPE(*)
(“assumed type”) dummy argument is permitted in a BIND(C)
procedure.
It interoperates with a C argument declared as “void *
”.
There is no difference between scalar and assumed-size on the C side, but on the Fortran side,
if the dummy argument is scalar the actual argument must also be scalar,
and if the dummy argument is an array, the actual argument must also be an array.
Because an actual argument can be passed directly to a TYPE(*)
dummy,
the C_LOC
function is not required, and so there is no need for the TARGET
attribute
on the actual argument.
For example,
Program type_star_example Interface Function checksum(scalar,size) Bind(C) Use Iso_C_Binding Type(*) scalar Integer(C_int),Value :: size Integer(C_int) checksum End Function End Interface Type myvec3 Double Precision v(3) End Type Type(myvec3) x Call Random_Number(x%v) Print *,checksum(x,Storage_Size(x)/8) End Program int checksum(void *a,int n) { int i; int res = 0; unsigned char *p = a; for (i=0; i<n; i++) res = 0x3fffffff&((res<<1) + p[i]); return res; }
BIND(C)
procedure can have optional arguments.
Such arguments cannot also have the VALUE
attribute.
An absent optional argument of a BIND(C)
procedure is
indicated by passing a null pointer argument.
For example,
Program optional_example Use Iso_C_Binding Interface Function f(a,b) Bind(C) Import Integer(C_int),Intent(In) :: a Integer(C_int),Intent(In),Optional :: b Integer(C_int) f End Function End Interface Integer(C_int) x,y x = f(3,14) y = f(23) Print *,x,y End Program int f(int *arg1,int *arg2) { int res = *arg1; if (arg2) res += *arg2; return res; }The second reference to
f
is missing the optional argument b
,
so a null pointer will be passed for it.
This will result in the output:
17 23