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++.

Calls Between C and C++ Functions

The following requirements apply when making calls between functions written in C and C++:
  • In Cray C++, the extern "C" linkage is required when declaring an external function that is written in Cray C or when declaring a Cray C++ function that is to be called from Cray C. Normally the compiler mangles function names to encode information about the function's prototype in the external name; this prevents direct access to these function names from a C function. The extern "C" keyword prevents the compiler from performing name mangling.
  • The program must be linked using the CC command.
  • The program's main routine must be C or C++ code compiled using the CC command.

Objects can be shared between C and C++. There are some Cray C++ objects that are not accessible to Cray C functions, such as classes. The following object types can be shared directly:

  • Integral and floating types.
  • Structures and unions that are declared identically in C and C++. In order for structures and unions to be shared, they must be declared with identical members in the identical order.
  • Arrays and pointers to the above types.

C_add_func is called by the Cray C++ main program:

#include <iostream.h>

extern "C" int C_add_func(int, int);
int global_int = 123;

main()
{
  int res, i;

  cout << "Start C++ main" << endl;

  /* Call C function to add two integers and return result. */

 cout << "Call C C_add_func" << endl;
 res = C_add_func(10, 20);
 cout << "Result of C_add_func = " << res << endl;
 cout << "End C++ main << endl;
}
#include <stdio.h>

extern int global_int;

int C_add_func(int p1, int p2)
{
    printf("\tStart C function C_add_func.\n");
    printf("\t\tp1 = %d\n", p1);
    printf("\t\tp2 = %d\n", p2);
    printf("\t\tglobal_int = %d\n", global_int);
    return p1 + p2;
}
Start C++ main
Call C C_add_func
        Start C function C_add_func.
                p1 = 10
                p2 = 20
                global_int = 123
Result of C_add_func = 30
End C++ main

Call Fortran Functions and Subroutines from C or C++

The following conditions are required to call Fortran Functions and Subroutines from C or C++:
  • Fortran uses the call-by-address convention. C and C++ use the call-by-value convention, which means that only pointers should be passed to Fortran subprograms.
  • Fortran arrays are in column-major order. C and C++ arrays are in row-major order. This indicates which dimension is indicated by the first value in an array element subscript.
  • Single-dimension arrays of signed 32-bit integers and single-dimension arrays of 32-bit floating-point numbers are the only aggregates that can be passed as parameters without changing the arrays.
  • Fortran character pointers and character pointers from Cray C and C++ are incompatible.
  • Fortran logical values and the Boolean values from C and C++ are not fully compatible.
  • External C and C++ variables are stored in common blocks of the same name, making them readily accessible from Fortran programs if the C or C++ variable is in uppercase.
  • When declaring Fortran functions or objects in C or C++, the name must be specified in all uppercase letters, digits, or underscore characters and consist of 31 or fewer characters.
  • In Cray C, Fortran functions can be declared using the fortran keyword. The fortran keyword is not available in Cray C++. Instead, Fortran functions must be declared by specifying extern "C".

Because Fortran subroutines expect arguments to be passed by pointers rather than by value, C and C++ functions called from Fortran subroutines must pass pointers rather than values.

All argument passing in Cray C is strictly by value. To prepare for a function call between two Cray C functions, a copy is made of each actual argument. A function can change the values of its formal parameters, but these changes cannot affect the values of the actual arguments. It is possible, however, to pass a pointer. (All array arguments are passed by this method.) This capability is analogous to the Fortran method of passing arguments.

In addition to passing by value, Cray C++ also provides passing by reference.

C and C++ arrays are stored in memory in row-major order. Fortran arrays are stored in memory in column-major order. For example, the C or C++ array declaration int A[3][2] is stored in memory as:
A[0][0]A[0][1]
A[1][0]A[1][1]
A[2][0]A[2][1]
The previously defined array is viewed linearly in memory as:
A[0][0] A[0][1] A[1][0] A[1][1] A[2][0] A[2][1]
The Fortran array declaration INTEGER A(3,2) is stored in memory as:
A(1,1)A(2,1)A(3,1)
A(1,2)A(2,2)A(3,2)
The previously defined array is viewed linearly in memory as:
A(1,1) A(2,1) A(3,1) A(1,2) A(2,2) A(3,2)

When an array is shared between Cray C, C++, and Fortran, its dimensions are declared and referenced in C and C++ in the opposite order in which they are declared and referenced in Fortran. Arrays are zero-based in C and C++ and are one-based in Fortran, so in C and C++, subtract 1 from the array subscripts that would normally be used in Fortran.

For example, using the Fortran declaration of array A in the preceding example, the equivalent declaration in C or C++ is:
int a[2][3];
The following list shows how to access elements of the array from Fortran and from C or C++:
FortranC or C++
A(1,1)A[0][0]
A(2,1)A[0][1]
A(3,1)A[0][2]
A(1,2)A[1][0]
A(2,2)A[1][1]
A(3,2)A[1][2]

Logical and character data need special treatment for calls between C or C++ and Fortran. Fortran has a character descriptor that is incompatible with a character pointer in C and C++. The techniques used to represent logical (Boolean) values also differ between Cray C, C++, and Fortran.

Mechanisms used to convert one type to the other are provided by the fortran.h header file and conversion macros shown in the following list:
MacroDescription
_btolConversion utility that converts a 0 to a Fortran logical .FALSE. and a nonzero value to a Fortran logical .TRUE.
_ltobConversion utility that converts a Fortran logical .FALSE. to a 0 and a Fortran logical .TRUE. to a 1.

The following example demonstrates how external C and C++ variables are accessible in Fortran named common blocks. It shows a C or C++ function calling a Fortran subprogram, the associated Fortran subprogram, and the associated input and output.

In this example, the C or C++ structure _st is accessed in the Fortran subprogram as common block ST. The Fortran common block ST will be converted to lower case with a trailing underscore added.

The name of the structure and the converted Fortran common block name must match. The C and C++ structure member names and the Fortran common block member names do not have to match, as is shown in this example.

The following Cray C main program calls the Fortran subprogram FCTN:
#include <stdio.h>
struct
{
  int i;
  double a[10];
  long double d;
} _st;

main()
{
   int i;

   /* initialize struct _st */
   _st.I = 12345;

   for (i = 0; i < 10; i++)
      _st.a[i] = i;

   _st.d = 1234567890.1234567890L;

   /* print out the members of struct _st */
   printf("In C: _st.i = %d, _st.d = %20.10Lf\n", _st.i, _st.d);
   printf("In C: _st.a = ");
   for (i = 0; i < 10; i++)
      printf("%4.1f", _st.a[i]);
   printf("\n\n");

   /* call the fortran function */
   FCTN();
}
The following example is the Fortran subprogram FCTN called by the previous Cray C main program:
C *********** Fortran subprogram (f.f): ***********

    SUBROUTINE FCTN

    COMMON /ST/STI, STA(10), STD
    INTEGER STI
    REAL STA
    DOUBLE PRECISION STD

INTEGER I

    WRITE(6,100) STI, STD
100 FORMAT ('IN FORTRAN: STI = ', I5, ', STD = ', D25.20)
    WRITE(6,200) (STA(I), I = 1,10)
200 FORMAT ('IN FORTRAN: STA =', 10F4.1)
    END
The previous Cray C and Fortran examples are executed by the following commands, and they produce the output shown:
% cc -c c.c
% ftn -c f.f
% ftn c.o f.o
% ./a.out
 ST.i = 12345, ST.d = 1234567890.1234567890
 In C: ST.a = 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0

 IN FORTRAN: STI = 12345, STD = .12345678901234567889D+10
 IN FORTRAN: STA = 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0

Fortran includes the concept of a common block. A common block is an area of memory that can be referenced by any program unit in a program. A named common block has a name specified in names of variables or arrays stored in the block. A blank common block, sometimes referred to as blank common, is declared in the same way, but without a name.There is no way to access blank common from C or C++ similar to accessing a named common block. However, a simple Fortran function can be written to return the address of the first word in blank common to the C or C++ program and then use that as a pointer value to access blank common.

Access Fortran blank common from C or C++ Code

#include <stdio.h>

struct st
{
  float a;
  float b[10];
} *ST;

#ifdef __cplusplus
  extern "C" struct st *MYCOMMON(void);
  extern "C" void FCTN(void);
#else
  fortran struct st *MYCOMMON(void);
  fortran void FCTN(void);
#endif

main()
{
    int i;

    ST = MYCOMMON();
    ST->a = 1.0;
    for (i = 0; i < 10; i++)
        ST->b[i] = i+2;
    printf("\n In C and C++\n");
    printf("     a = %5.1f\n", ST->a);
    printf("     b = ");
    for (i = 0; i < 10; i++)
        printf("%5.1f ", ST->b[i]);
    printf("\n\n");

    FCTN();
}
  
The following Fortran subroutine uses blank common and is called from main() above.

SUBROUTINE FCTN
COMMON // STA,STB(10)
PRINT *, "IN FORTRAN"
PRINT *, "    STA = ",STA
PRINT *, "    STB = ",STB
STOP
END

INTEGER(KIND=8) FUNCTION MYCOMMON()
COMMON // A
MYCOMMON = LOC(A)
RETURN
END
  

The previous Cray C and Fortran code is executed by the following commands, and produces the output shown:


% cc -c c1.c
% ftn -c f2.f
% ftn c1.o f1.o
% ./a.out
 In C and C++
     a =   1.0
     b =   2.0   3.0   4.0   5.0   6.0   7.0   8.0   9.0  10.0  11.0 

 IN FORTRAN
     STA =  1.
     STB =  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.,  10.,  11.
 STOP  
  

Call a Fortran Program from Cray C++

Here is an example of a Cray C function that calls a Fortran subprogram. The Fortran subprogram example follows the Cray C function example, and the input and output from this sequence follows the Fortran subprogram example.

This example assumes that the Cray Fortran function is compiled with the -s default32 option enabled. The examples will not work if the -s default64 option is enabled.
/*                 C program (main.c):                   */

#include <stdio.h>
#include <string.h>
#include <fortran.h>

/* Declare prototype of the Fortran function. Note the last */
/* argument passes the length of the first argument. */
fortran double FTNFCTN (char *, int *, int);

double FLOAT1 = 1.6;
double FLOAT2; /* Initialized in FTNFCTN */

main()
{
     int clogical, ftnlogical, cstringlen;
     double rtnval;
     char *cstring = "C Character String";

/* Convert clogical to its Fortran equivalent */
     clogical = 1;
     ftnlogical = _btol(clogical);

/* Print values of variables before call to Fortran function */
     printf(" In main: FLOAT1 = %g; FLOAT2 = %g\n",
          FLOAT1, FLOAT2);
     printf(" Calling FTNFCTN with arguments:\n");
     printf(" string = \"%s\"; logical = %d\n\n", cstring, clogical);
     cstringlen = strlen(cstring);
     rtnval = FTNFCTN(cstring, &ftnlogical, cstringlen);

/* Convert ftnlogical to its C equivalent */
     clogical = _ltob(&ftnlogical);

/* Print values of variables after call to Fortran function */
     printf(" Back in main: FTNFCTN returned %g\n", rtnval);
     printf(" and changed the two arguments:\n");
     printf(" string = \"%.*s\"; logical = %d\n",
     cstringlen, cstring, clogical);
}
C                  Fortran subprogram (ftnfctn.f):

     FUNCTION FTNFCTN(STR, LOG)
     REAL FTNFCTN
     CHARACTER*(*) STR
     LOGICAL LOG

     COMMON /FLOAT1/FLOAT1
     COMMON /FLOAT2/FLOAT2
     REAL FLOAT1, FLOAT2
     DATA FLOAT2/2.4/ ! FLOAT1 INITIALIZED IN MAIN

C      PRINT CURRENT STATE OF VARIABLES
       PRINT*, ' IN FTNFCTN: FLOAT1 = ', FLOAT1,
      1 ';FLOAT2 = ', FLOAT2
       PRINT*, ' ARGUMENTS: STR = "', STR, '"; LOG = ', LOG

C      CHANGE THE VALUES FOR STR(ING) AND LOG(ICAL)
       STR = 'New Fortran String'
       LOG = .FALSE.

       FTNFCTN = 123.4
       PRINT*, ' RETURNING FROM FTNFCTN WITH ', FTNFCTN
       PRINT*
       RETURN
       END
The previous Cray C function and Fortran subprogram are executed by the following commands and produce the following output:
% cc -c main.c
% ftn -c ftnfctn.f
% ftn main.o ftnfctn.o
% ./a.out
In main: FLOAT1 = 1.6;  FLOAT2 = 2.4
Calling FTNFCTN with arguments:
string = "C Character String"; logical = 1

IN FTNFCTN: FLOAT1 = 1.6; FLOAT2 = 2.4
ARGUMENTS:   STR = "C Character String"; LOG = T
RETURNING FROM FTNFCTN WITH 123.4
Back in main: FTNFCTN returned 123.4
and changed the two arguments:
string = "New Fortran String"; logical = 0
The following example illustrates how a Fortran program can be called from a Cray C++ program:
#include <iostream>
using namespace std;
extern "C" int fortran_add_ints_(int *arg1, int &arg2);

main()
{
     int num1, num2, res;
     cout << "Start C++ main" << endl << endl;
     //Call FORTRAN function to add two integers and return result.
     //Note that the second argument is a reference parameter so
     //it is not necessary to take the address of the
     //variable num2.

     num1 = 10;
     num2 = 20;
     cout << "Before Call to FORTRAN_ADD_INTS" << endl;
     res = fortran_add_ints_(&num1, num2);
     cout << "Result of FORTRAN Add = " << res << endl << endl;
     cout << "End C++ main" << endl;
}
The Fortran program that is called from the Cray C++ main function in the preceding example is as follows:
INTEGER FUNCTION FORTRAN_ADD_INTS(Arg1, Arg2)
INTEGER Arg1, Arg2

PRINT *," FORTRAN_ADD_INTS, Arg1,Arg2 = ", Arg1, Arg2
FORTRAN_ADD_INTS = Arg1 + Arg2
END
The output from the execution of the preceding example is as follows:
Start C++ main

Before Call to FORTRAN_ADD_INTS
  FORTRAN_ADD_INTS, Arg1,Arg2 = 10, 20
Result of FORTRAN Add = 30

End C++ main

Calling a C or C++ Function from Fortran

Two methods can be used to call C or C++ functions from Fortran:
  • Standard Fortran/C Interoperability
  • Portable Interoperability Mechanism

For more information about C interoperability, see the current Fortran standard. 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 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. For more information about C interoperability, see the current Fortran standard.

When calling a Cray C++ function from a Fortran program, observe the following rules:
  • The Cray C++ function must be declared with extern "C" linkage.
  • The program must be linked using the CC() command.
  • The program's main routine must be C or C++ code compiled using the CC command.

Call a C function from Fortran

Fortran program main.f source code:
C  Fortran program (main.f):

     PROGRAM MAIN

     REAL CFCTN
     COMMON /FLOAT1/FLOAT1
     COMMON /FLOAT2/FLOAT2
     REAL FLOAT1, FLOAT2
     DATA FLOAT1/1.6/ ! FLOAT2 INITIALIZED IN cfctn.c
     LOGICAL LOG
     CHARACTER*24 STR
     REAL RTNVAL

C INITIALIZE VARIABLES STR(ING) AND LOG(ICAL)
     STR = 'Fortran Character String'
     LOG = .TRUE.

C PRINT VALUES OF VARIABLES BEFORE CALL TO C FUNCTION
     PRINT*, 'In main.f: FLOAT1 = ', FLOAT1,
    1               '; FLOAT2 = ', FLOAT2
     PRINT*, 'Calling cfctn.c with these arguments: '
     PRINT*, 'LOG = ', LOG
     PRINT*, 'STR = ', STR

     RTNVAL = CFCTN(STR, LOG)

C PRINT VALUES OF VARIABLES AFTER CALL TO C FUNCTION
     PRINT*, 'Back in main.f:: cfctn.c returned ', RTNVAL
     PRINT*, 'and changed the two arguments to: '
     PRINT*, 'LOG = ', LOG
     PRINT*, 'STR = ', STR

     END PROGRAM
Compile main.f, creating main.o:
% ftn -c main.f
C function cfctn.c source code:

/*   C function (cfctn.c)    */
#include <fortran.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

float FLOAT1;    /* Initialized in MAIN */
float FLOAT2 = 2.4;

/* The slen argument passes the length of string in str */
float cfctn_(char * str, int *log, int slen)
{
  int clog;
  float rtnval;
  char *cstring;

/* Convert log passed from Fortran MAIN */
/* into its C equivalent */
  cstring = malloc(slen+1);
  strncpy(cstring, str, slen);
  cstring[slen] = '\0';
  clog = _ltob(log);

/* Print the current state of the variables */
  printf(" In CFCTN: FLOAT1 = %.1f; FLOAT2 = %.1f\n",
        FLOAT1, FLOAT2);
  printf(" Arguments: str = '%s'; log = %d\n",
  cstring, clog);

/* Change the values for str and log */
  strncpy(str, "C Character String ", 24);
  *log = 0;

  rtnval = 123.4;
  printf(" Returning from CFCTN with %.1f\n\n", rtnval);
  return(rtnval);
}
Compile cfctn.c, creating cfctn.o:
% cc -c cfctn.c
Link main.o and cfctn.o, creating executable interlang1:
% % ftn -o interlang1 main.o cfctn.o
Run program interlang1:
% ./interlang1
Program output:
In main.f: FLOAT1 = 1.60000002 ; FLOAT2 = 2.4000001
 Calling cfctn.c with these arguments:
 LOG = T
 STR = Fortran Character String
 In CFCTN: FLOAT1 = 1.6; FLOAT2 = 2.4
 Arguments: str = 'Fortran Character String'; log = 1
 Returning from CFCTN with 123.4

 Back in main.f:: cfctn.c returned 123.400002
 and changed the two arguments to:
 LOG = F
 STR = C Character String

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.

The Fortran 2008 standard describes interoperabilty features for:
Intrinsic Types
The Fortran intrinsic module ISO_C_BINDING 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 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.
Derived Types and Structures
Use the BIND attribute when creating an interoperable type:

USE ISO_C_BINDING
TYPE, BIND(C) :: THIS_TYPE
    . . .
END TYPE THIS_TYPE
Global Variables
Use the BIND attribute 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_BINDING provides a derived type, c_ptr, that interoperates with any C pointer type. Also, Fortran named constant c_null_ptr is 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:
FUNCTION MYFUNCTION(X, Y), BIND(C, NAME='C_Myfunction')
A function result must be scalar and of interoperable type. A subroutine prototype must have a void result.
TS 29113 describes further interoperability features including:
C descriptors
ISO_Fortran_binding.h defines C structure CFI_cdesc_t which 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.

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