Interfacing Fortran with C can be highly beneficial, as it allows you to leverage the strengths of both languages. Fortran is known for its performance in numerical computations, while C provides more control over system-level programming. This section will guide you through the process of calling C functions from Fortran and vice versa.

Key Concepts

  1. Interoperability: Understanding how Fortran and C can work together.
  2. ISO_C_BINDING Module: Using the Fortran module that facilitates interoperability with C.
  3. Calling C Functions from Fortran: Steps and examples.
  4. Calling Fortran Functions from C: Steps and examples.
  5. Data Type Mapping: Ensuring compatibility between Fortran and C data types.

ISO_C_BINDING Module

The ISO_C_BINDING module in Fortran provides the necessary tools to interface with C. It includes constants and derived types that map Fortran types to C types.

Example

program c_interop_example
  use iso_c_binding
  implicit none

  interface
    subroutine c_function(x) bind(C, name="c_function")
      use iso_c_binding
      real(c_double), value :: x
    end subroutine c_function
  end interface

  real(c_double) :: x = 3.14

  call c_function(x)

end program c_interop_example

In this example:

  • The use iso_c_binding statement imports the module.
  • The interface block declares the C function c_function with the bind(C, name="c_function") attribute, indicating that it is a C function.
  • The real(c_double) type ensures that the Fortran variable x is compatible with the C double type.

Calling C Functions from Fortran

Steps

  1. Declare the C Function: Use the interface block with the bind(C) attribute.
  2. Ensure Data Type Compatibility: Use ISO_C_BINDING to map Fortran types to C types.
  3. Call the Function: Use the call statement as you would with any Fortran subroutine.

Example

C Code (c_code.c):

#include <stdio.h>

void c_function(double x) {
    printf("Value from Fortran: %f\n", x);
}

Fortran Code (fortran_code.f90):

program call_c_function
  use iso_c_binding
  implicit none

  interface
    subroutine c_function(x) bind(C, name="c_function")
      use iso_c_binding
      real(c_double), value :: x
    end subroutine c_function
  end interface

  real(c_double) :: x = 3.14

  call c_function(x)

end program call_c_function

Compilation and Execution

gcc -c c_code.c
gfortran -o call_c_function fortran_code.f90 c_code.o
./call_c_function

Calling Fortran Functions from C

Steps

  1. Declare the Fortran Function: Use the bind(C) attribute in the Fortran code.
  2. Ensure Data Type Compatibility: Use ISO_C_BINDING to map Fortran types to C types.
  3. Call the Function: Use the function name in the C code.

Example

Fortran Code (fortran_code.f90):

module fortran_module
  use iso_c_binding
  implicit none

contains

  subroutine fortran_function(x) bind(C, name="fortran_function")
    real(c_double), intent(in) :: x
    print *, "Value from C: ", x
  end subroutine fortran_function

end module fortran_module

C Code (c_code.c):

#include <stdio.h>

void fortran_function(double *x);

int main() {
    double x = 3.14;
    fortran_function(&x);
    return 0;
}

Compilation and Execution

gfortran -c fortran_code.f90
gcc -o call_fortran c_code.c fortran_code.o -lgfortran
./call_fortran

Data Type Mapping

The ISO_C_BINDING module provides constants to map Fortran types to C types. Here is a table of common mappings:

Fortran Type C Type ISO_C_BINDING Constant
integer int C_INT
real float C_FLOAT
double precision double C_DOUBLE
character(len=1) char C_CHAR
logical _Bool C_BOOL

Practical Exercise

Task

Write a Fortran program that calls a C function to compute the square of a number.

Solution

C Code (square.c):

double square(double x) {
    return x * x;
}

Fortran Code (main.f90):

program call_square
  use iso_c_binding
  implicit none

  interface
    function square(x) bind(C, name="square")
      use iso_c_binding
      real(c_double) :: square
      real(c_double), value :: x
    end function square
  end interface

  real(c_double) :: x = 5.0
  real(c_double) :: result

  result = square(x)
  print *, "Square of ", x, " is ", result

end program call_square

Compilation and Execution

gcc -c square.c
gfortran -o call_square main.f90 square.o
./call_square

Conclusion

In this section, you learned how to interface Fortran with C using the ISO_C_BINDING module. You now know how to call C functions from Fortran and vice versa, ensuring data type compatibility. This knowledge allows you to leverage the strengths of both languages in your projects. In the next module, we will explore best practices and optimization techniques to enhance your Fortran programs.

© Copyright 2024. All rights reserved