Interlanguage Communication
The C and C++ compilers provide mechanisms for declaring external functions written in other languages. This enables the writing of portions of an application in C, C++, Fortran, or assembly language, which can be useful in cases where the other languages provide performance advantages or utilities not available in C or C++.
The C and C++ compilers provide mechanisms for declaring external functions written in other languages. This enables the writing of portions of an application in C, C++, Fortran, or assembly language, which can be useful in cases where the other languages provide performance advantages or utilities not available in C or C++.
Fortran, C, C++ Interoperability
The Cray Compiler supports interoperability mechanisms specfied in the Fortran 2008 standard, ISO/IEC 1539-1:2010, and TS 29113 Further Interoperability of Fortran and C.
- Intrinsic Types
- The Fortran intrinsic module
ISO_C_BINDINGprovides interoperability between Fortran intrinsic types and C types. TheISO_C_BINDINGmodule provides named constants which can be used asKINDtype parameters, compatible with C types. - Derived Types and Structures
- Use the
BINDattribute when creating an interoperable type:USE ISO_C_BINDING TYPE, BIND(C) :: THIS_TYPE . . . END TYPE THIS_TYPE - Global Variables
- Use the
BINDattribute with a common block declaration, or module variable:USE ISO_C_BINDING INTEGER(C_INT), BIND(C) :: EXTERN INTEGER(C_LONG) :: CVAR BIND(C, NAME='var') :: CVAR COMMON /A/ I, J REAL(C_FLOAT) :: I, J BIND(C) :: /A/ - Pointers
ISO_C_BINDINGprovides a derived type,c_ptr, that interoperates with any C pointer type. Also, Fortran named constantc_null_ptris equivalent to the C value NULL.- Subroutines and Function
- Declare a Fortran procedure with the BIND attribute. Procedure arguments must be of interoperable type. By default the Fortran compiler converts the procedure name to lower-case (
myfunction); this is the binding label, or corresponding name which is known to the C compiler.FUNCTION MYFUNCTION(X, Y), BIND(C)Specify a different binding label:A function result must be scalar and of interoperable type. A subroutine prototype must have a void result.FUNCTION MYFUNCTION(X, Y), BIND(C, NAME='C_Myfunction')
- C descriptors
- ISO_Fortran_binding.h defines C structure
CFI_cdesc_twhich facilitates using Fortran data objects from within a C function. - ISO_Fortran binding.h
- Contains additional C structure definitions and macro definitions to interoperate with an allocatable, or data pointer argument.
BIND(C) Syntax
The proc-language-binding-spec specification allows Fortran programs to interoperate with C objects. The optional commas in FUNCTION name(), BIND(C) are Cray extensions to the Fortran standard.
ISO_C_BINDING
The ISO_C_BINDING module provides interoperability between Fortran intrinsic types and C types. The ISO_C_BINDING module provides named constants which can be used as KIND type parameters, compatible with C types.
In addition to the named constants required by the Fortran 2008 standard, Cray compiler provides, as an extension, definitions for 128-bit floating, and complex types. C_FLOAT128 and C_FLOAT128_COMPLEX correspond to C types __float128 and __float128 complex.
Interlanguage Communication Examples
Interlanguage Communication using Common Block/Global
// common_c.c : example of function called from common.f90
#include <stdio.h>
#include <stdlib.h>
#include <ISO_Fortran_binding.h>
// globals that match up to the common blocks in common.f90
float c_single;
struct common {
double var1;
int var2;
} multiple;
int c_int_array[100];
// c function called from Fortran
void global_var_common()
{
int i;
// just prints and sets the globals
printf(" In global_var_common\n");
printf(" c_single: %f\n", c_single);
printf(" multiple: %f, %d\n", multiple.var1, multiple.var2 );
printf(" c_int_array: %d, %d\n", c_int_array[0], c_int_array[99]);
c_single = 2 * c_single;
multiple.var1 = 77.77;
multiple.var2 = 17;
for(i=0; i<100; i++ ) {
c_int_array[i] = c_int_array[i] * 3;
}
} // end of global_var_common
! common.f90
! Needs common_c.c
program common_block
use, intrinsic :: iso_c_binding
! use check_error
implicit none
!
! declare the common blocks for c globals
! one with a single real variable
real(c_float) r_var
common /c_single/ r_var
! one with an integer array
integer i_array(100)
common / array / i_array
! one with two variables
real(c_double) :: var1
integer(c_int) :: var2
common / multiple / var1, var2
! do the bind c on the common blocks, renaming one
BIND(C,name="c_int_array") :: / array /
BIND(C) :: / multiple /, /c_single/
call sub1()
end program common_block
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
subroutine sub1( )
use, intrinsic :: iso_c_binding
! declare the common blocks for c globals
! one with a single real variable
real(c_float) r_var
common /c_single/ r_var
! one with an integer array
integer i_array(100)
common / array / i_array
real(c_double) var1
integer(c_int) var2
common / multiple / var1, var2
! do the bind c on the common blocks, renaming array
BIND(C,name="c_int_array") :: / array /
BIND(C) :: / multiple /, /c_single/
interface
subroutine global_var_common( ) bind(c)
use,intrinsic :: iso_c_binding
implicit none
end subroutine global_var_common
end interface
r_var = -99.3
var1 = 88.88
var2 = -13
i_array = [(i,i=1,100)]
! call the c function
call global_var_common( )
print *, "In sub1"
print *, " r_var : ", r_var
print *, " var1 : ", var1
print *, " var2 : ", var2
print *, " array : ", i_array(1), i_array(100)
end subroutine
Interlanguage Communication using Derived Structure
// c program that calls the Fortran subroutine with struct argument, f2008 C.11.3
//*********************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <ISO_Fortran_binding.h>
// declare the structure type
struct pass {
int lenc, lenf;
float *c, *f;
};
// prototype for the Fortran function
void simulation(long alpha, double *beta, long *gamma, double delta[], struct pass *arrays);
// program that calls the Fortran subroutine
int main ( )
{
int i;
long alpha, gamma;
double beta, delta[100];
struct pass arrays;
alpha = 1234L;
gamma = 5678L;
beta = 12.34;
for(i=0; i<100; i++ ) {
delta[i] = i+1;
}
// fill in some of the structure
arrays.lenc = 100;
arrays.lenf = 0;
arrays.c = (float *) malloc( 100*sizeof(float) );
arrays.f = NULL;
for(i=0; i<100; i++ ) {
arrays.c[i] = 2*(i+1);
}
// reference the Fortran subroutine
simulation(alpha, &beta, &gamma, delta, &arrays);
printf(" After simulation\n");
printf(" alpha: %d, beta: %f\n", alpha, beta );
printf(" gamma: %d\n", gamma );
printf(" arrays.lenc: %d\n", arrays.lenc);
printf(" arrays.c[0],[arrays.lenc-1],: %f, %f\n", arrays.c[0], arrays.c[arrays.lenc-1]);
printf(" arrays.lenf: %d\n", arrays.lenf);
printf(" arrays.f[0],[arrays.lenf-1],: %f, %f\n", arrays.f[0], arrays.f[arrays.lenf-1]);
} // end of main
! Example derived type/structure interoperability, f2008 C.11.3
!**************************************************************
subroutine simulation(alpha, beta, gamma, delta, arrays) bind(c)
use, intrinsic :: iso_c_binding
implicit none
integer (c_long), value :: alpha
real (c_double), intent(inout) :: beta
integer (c_long), intent(out) :: gamma
real (c_double),dimension(*),intent(in) :: delta
type, bind(c) :: pass
integer (c_int) :: lenc, lenf
type (c_ptr) :: c, f
end type pass
type (pass), intent(inout) :: arrays
real (c_float), allocatable, target, save :: eta(:)
real (c_float), pointer :: c_array(:)
integer i
print *, "In simulation"
print *, " alpha: ", alpha, ", beta: ", beta
print *, " delta(1),(100): ", delta(1), delta(100)
! associate c_array with an array allocated in c
call c_f_pointer (arrays%c, c_array, [arrays%lenc])
print *, " c_array(1),(arrays%lenc): ", c_array(1), c_array(arrays%lenc)
! allocate an array and make it available in c
arrays%lenf = 100
allocate (eta(arrays%lenf))
arrays%f = c_loc(eta)
eta = [(i*3,i=1,arrays%lenf)]
! change argument values
c_array = c_array * 2.0
gamma = 77
beta = -55.66
end subroutine simulation
Interlanguage Communication using Module
// c function called from module.f90
#include <stdio.h>
#include <stdlib.h>
#include <ISO_Fortran_binding.h>
// globals that match up to the module variables in module.f90
float r_var;
double var1;
int var2;
int c_int_array[100];
// c function called from Fortran
void global_var_module()
{
int i;
// just prints and sets the globals
printf(" In global_var_module\n");
printf(" r_var : %f\n", r_var);
printf(" var1 : %f\n", var1 );
printf(" var2 : %d\n", var2 );
printf(" c_int_array: %d, %d\n", c_int_array[0], c_int_array[99]);
r_var = 2 * r_var;
var1 = 77.77;
var2 = 17;
for(i=0; i<100; i++ ) {
c_int_array[i] = c_int_array[i] * 3;
}
} // end of global_var_module
! Example of module/global variable interoperability.
! Needs c function from module_c.c
! ********************************************************************
module module_example_mod
use, intrinsic :: iso_c_binding
real(c_float) r_var
integer i_array(100)
real(c_double) :: var1
integer(c_int) :: var2
BIND(C,name="c_int_array") :: i_array
BIND(C) :: r_var, var1, var2
end module module_example_mod
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
program module_example
use module_example_mod
implicit none
call sub1()
end program module_example
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
subroutine sub1( )
use module_example_mod
interface ! for the c function
subroutine global_var_module( ) bind(c)
use,intrinsic :: iso_c_binding
implicit none
end subroutine global_var_module
end interface
r_var = -99.3
var1 = 88.88
var2 = -13
i_array = [(i,i=1,100)]
! call the c function
call global_var_module( )
print *, "In sub1"
print *, " r_var : ", r_var
print *, " var1 : ", var1
print *, " var2 : ", var2
print *, " array : ", i_array(1), i_array(100)
end subroutine