Interoperability with C#
Since Fortran 2003 (ISO/IEC 1539-1:2004(E)) there is a
standardized way to generate procedure and derived-type
declarations and global variables that are interoperable with C
(ISO/IEC 9899:1999). The BIND(C)
attribute has been added
to inform the compiler that a symbol shall be interoperable with C;
also, some constraints are added. Note, however, that not
all C features have a Fortran equivalent or vice versa. For instance,
neither C’s unsigned integers nor C’s functions with variable number
of arguments have an equivalent in Fortran.
Note that array dimensions are reversely ordered in C and that arrays in
C always start with index 0 while in Fortran they start by default with
1. Thus, an array declaration A(n,m)
in Fortran matches
A[m][n]
in C and accessing the element A(i,j)
matches
A[j-1][i-1]
. The element following A(i,j)
(C: A[j-1][i-1]
;
assuming i < n) in memory is A(i+1,j)
(C: A[j-1][i]
).
Intrinsic Types#
In order to ensure that exactly the same variable type and kind is used
in C and Fortran, you should use the named constants for kind parameters
that are defined in the ISO_C_BINDING
intrinsic module.
That module contains named constants of character type representing
the escaped special characters in C, such as newline.
For a list of the constants, see ISO_C_BINDING.
For logical types, please note that the Fortran standard only guarantees
interoperability between C99’s _Bool
and Fortran’s C_Bool
-kind
logicals and C99 defines that true
has the value 1 and false
the value 0. Using any other integer value with GNU Fortran’s LOGICAL
(with any kind parameter) gives an undefined result. (Passing other integer
values than 0 and 1 to GCC’s _Bool
is also undefined, unless the
integer is explicitly or implicitly casted to _Bool
.)
Derived Types and struct#
For compatibility of derived types with struct
, use
the BIND(C)
attribute in the type declaration. For instance, the
following type declaration
USE ISO_C_BINDING
TYPE, BIND(C) :: myType
INTEGER(C_INT) :: i1, i2
INTEGER(C_SIGNED_CHAR) :: i3
REAL(C_DOUBLE) :: d1
COMPLEX(C_FLOAT_COMPLEX) :: c1
CHARACTER(KIND=C_CHAR) :: str(5)
END TYPE
matches the following struct
declaration in C
struct {
int i1, i2;
/* Note: "char" might be signed or unsigned. */
signed char i3;
double d1;
float _Complex c1;
char str[5];
} myType;
Derived types with the C binding attribute shall not have the sequence
attribute, type parameters, the extends
attribute, nor type-bound
procedures. Every component must be of interoperable type and kind and may not
have the pointer
or allocatable
attribute. The names of the
components are irrelevant for interoperability.
As there exist no direct Fortran equivalents, neither unions nor structs with bit field or variable-length array members are interoperable.
Interoperable Global Variables#
Variables can be made accessible from C using the C binding attribute,
optionally together with specifying a binding name. Those variables
have to be declared in the declaration part of a MODULE
,
be of interoperable type, and have neither the pointer
nor
the allocatable
attribute.
MODULE m
USE myType_module
USE ISO_C_BINDING
integer(C_INT), bind(C, name="_MyProject_flags") :: global_flag
type(myType), bind(C) :: tp
END MODULE
Here, _MyProject_flags
is the case-sensitive name of the variable
as seen from C programs while global_flag
is the case-insensitive
name as seen from Fortran. If no binding name is specified, as for
tp
, the C binding name is the (lowercase) Fortran binding name.
If a binding name is specified, only a single variable may be after the
double colon. Note of warning: You cannot use a global variable to
access errno
of the C library as the C standard allows it to be
a macro. Use the IERRNO
intrinsic (GNU extension) instead.
Interoperable Subroutines and Functions#
Subroutines and functions have to have the BIND(C)
attribute to
be compatible with C. The dummy argument declaration is relatively
straightforward. However, one needs to be careful because C uses
call-by-value by default while Fortran behaves usually similar to
call-by-reference. Furthermore, strings and pointers are handled
differently.
To pass a variable by value, use the VALUE
attribute.
Thus, the following C prototype
int func(int i, int *j)
matches the Fortran declaration
integer(c_int) function func(i,j)
use iso_c_binding, only: c_int
integer(c_int), VALUE :: i
integer(c_int) :: j
Note that pointer arguments also frequently need the VALUE
attribute,
see Working with C Pointers.
Strings are handled quite differently in C and Fortran. In C a string
is a NUL
-terminated array of characters while in Fortran each string
has a length associated with it and is thus not terminated (by e.g.
NUL
). For example, if you want to use the following C function,
#include <stdio.h>
void print_C(char *string) /* equivalent: char string[] */
{
printf("%s\n", string);
}
to print ‘Hello World’ from Fortran, you can call it using
use iso_c_binding, only: C_CHAR, C_NULL_CHAR
interface
subroutine print_c(string) bind(C, name="print_C")
use iso_c_binding, only: c_char
character(kind=c_char) :: string(*)
end subroutine print_c
end interface
call print_c(C_CHAR_"Hello World"//C_NULL_CHAR)
As the example shows, you need to ensure that the
string is NUL
terminated. Additionally, the dummy argument
string
of print_C
is a length-one assumed-size
array; using character(len=*)
is not allowed. The example
above uses c_char_"Hello World"
to ensure the string
literal has the right type; typically the default character
kind and c_char
are the same and thus "Hello World"
is equivalent. However, the standard does not guarantee this.
The use of strings is now further illustrated using the C library
function strncpy
, whose prototype is
char *strncpy(char *restrict s1, const char *restrict s2, size_t n);
The function strncpy
copies at most n
characters from
string s2
to s1
and returns s1
. In the following
example, we ignore the return value:
use iso_c_binding
implicit none
character(len=30) :: str,str2
interface
! Ignore the return value of strncpy -> subroutine
! "restrict" is always assumed if we do not pass a pointer
subroutine strncpy(dest, src, n) bind(C)
import
character(kind=c_char), intent(out) :: dest(*)
character(kind=c_char), intent(in) :: src(*)
integer(c_size_t), value, intent(in) :: n
end subroutine strncpy
end interface
str = repeat('X',30) ! Initialize whole string with 'X'
call strncpy(str, c_char_"Hello World"//C_NULL_CHAR, &
len(c_char_"Hello World",kind=c_size_t))
print '(a)', str ! prints: "Hello WorldXXXXXXXXXXXXXXXXXXX"
end
The intrinsic procedures are described in Intrinsic Procedures.
Working with C Pointers#
C pointers are represented in Fortran via the special opaque derived
type type(c_ptr)
(with private components). C pointers are distinct
from Fortran objects with the POINTER
attribute. Thus one needs to
use intrinsic conversion procedures to convert from or to C pointers.
For some applications, using an assumed type (TYPE(*)
) can be
an alternative to a C pointer, and you can also use library routines
to access Fortran pointers from C. See Further Interoperability of Fortran with C.
Here is an example of using C pointers in 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])
When converting C to Fortran arrays, the one-dimensional SHAPE
argument
has to be passed.
If a pointer is a dummy argument of an interoperable procedure, it usually
has to be declared using the VALUE
attribute. void*
matches TYPE(C_PTR), VALUE
, while TYPE(C_PTR)
alone
matches void**
.
Procedure pointers are handled analogously to pointers; the C type is
TYPE(C_FUNPTR)
and the intrinsic conversion procedures are
C_F_PROCPOINTER
and C_FUNLOC
.
Let us consider two examples of actually passing a procedure pointer from C to Fortran and vice versa. Note that these examples are also very similar to passing ordinary pointers between both languages. First, consider this code in 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);
}
A matching implementation for get_values
in Fortran, that correctly
receives the procedure pointer from C and is able to call it, is given
in the following 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
Next, we want to call a C routine that expects a procedure pointer argument and pass it a Fortran procedure (which clearly must be interoperable!). Again, the C function may be:
int
call_it (int (*func)(int), int arg)
{
return func (arg);
}
It can be used as in the following Fortran code:
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
Further Interoperability of Fortran with C#
GNU Fortran implements the Technical Specification ISO/IEC TS
29113:2012, which extends the interoperability support of Fortran 2003
and Fortran 2008 and is now part of the 2018 Fortran standard.
Besides removing some restrictions and constraints, the Technical
Specification adds assumed-type (TYPE(*)
) and assumed-rank
(DIMENSION(..)
) variables and allows for interoperability of
assumed-shape, assumed-rank, and deferred-shape arrays, as well as
allocatables and pointers. Objects of these types are passed to
BIND(C)
functions as descriptors with a standard interface,
declared in the header file <ISO_Fortran_binding.h>
.
Note: Currently, GNU Fortran does not use internally the array descriptor
(dope vector) as specified in the Technical Specification, but uses
an array descriptor with different fields in functions without the
BIND(C)
attribute. Arguments to functions marked BIND(C)
are converted to the specified form. If you need to access GNU Fortran’s
internal array descriptor, you can use the Chasm Language Interoperability
Tools, http://chasm-interop.sourceforge.net/.