Introduction to the ISO_C_BINDING Module
Modern Fortran defines a standardized way to interoperate with C through the intrinsic module iso_c_binding, introduced in Fortran 2003. It supplies portable kind parameters such as c_int, c_double, and c_float that guarantee a Fortran variable has exactly the same binary representation as the corresponding C type on the target platform, replacing the old, non-portable practice of guessing that a Fortran integer happened to match a C int. Without iso_c_binding, calling a C library from Fortran (or vice versa) relies on compiler-specific conventions that can silently break when you switch compilers or platforms.
Cricket analogy: Like agreeing on ICC's official pitch and ball specifications before an international match, so a bowler trained in Australia and a batter trained in India both know exactly what to expect, rather than each team guessing the other's local ground rules.
Calling C Functions from Fortran
To call a C function from Fortran, you write an explicit interface block declaring the function with the bind(c, name='c_function_name') attribute, matching each C parameter's type to its iso_c_binding equivalent (for example a C double* typically corresponds to a Fortran real(c_double), value or a pointer target depending on whether C expects a value or an address). The value attribute on a dummy argument is essential when the C function expects to receive an argument by value rather than by reference, since Fortran otherwise passes everything by reference by default, which would hand the C function a pointer where it expected a plain number.
Cricket analogy: Like an overseas fast bowler joining a domestic franchise: the coaching staff writes an explicit dossier translating his exact grip, run-up length, and release point into terms the local team understands, rather than assuming his technique needs no translation.
! Fortran side: calling C's sqrt() from libm via an explicit interface
module c_math
use, intrinsic :: iso_c_binding
implicit none
interface
function c_sqrt(x) bind(c, name='sqrt') result(res)
import :: c_double
real(c_double), value :: x
real(c_double) :: res
end function c_sqrt
end interface
end module c_math
program call_c
use c_math
implicit none
real(c_double) :: y
y = c_sqrt(2.0_c_double)
print *, 'sqrt(2) via C =', y
end program call_c
Exposing Fortran to C: the bind(c) Attribute
The interoperability is symmetric: a Fortran subroutine or function can be made callable from C by adding bind(c, name='...') to its own declaration, which fixes its external symbol name to match exactly what the C linker expects (Fortran compilers otherwise mangle names with case-folding and compiler-specific decoration). Derived types intended to cross the boundary must be declared with the bind(c) attribute too, so their member layout matches a C struct field-for-field with no hidden padding or descriptor overhead that a plain Fortran derived type (which may carry array descriptors) would otherwise introduce.
Cricket analogy: Like a domestic player being registered under one fixed, official name on the international team sheet so overseas commentators and scorers can identify him unambiguously, instead of each broadcaster using a different local nickname.
Mixing a plain (non-bind(c)) Fortran derived type into a C interface is a common and dangerous mistake: ordinary Fortran derived types can carry compiler-specific hidden metadata (for allocatable components, type-bound procedures, or array descriptors) that has no equivalent in a C struct, so the two languages will disagree about the memory layout and corrupt data silently. Always declare cross-language types with bind(c) and stick to interoperable component types.
Practical Workflow and Tooling
In practice, mixed Fortran/C projects are built by compiling each language's source with its own compiler and linking the resulting object files together (for example gfortran and gcc both produce standard object files that a single linker invocation can combine), often orchestrated by CMake's Fortran/C language support or a hand-written Makefile that tracks both toolchains. Because C has no notion of Fortran's array descriptors, arrays crossing the boundary are normally passed as a plain pointer to contiguous data (real(c_double), dimension(*) or type(c_ptr)) alongside an explicit integer size argument, since C has no built-in way to ask an incoming pointer how many elements it points to.
Cricket analogy: Like a franchise fielding both a local domestic scoring system and an international ICC scoring feed, with a dedicated liaison officer who reconciles the two into one official scoreboard, rather than assuming they merge automatically.
When passing a Fortran array to C, always pass its element count as a separate explicit integer(c_int) argument. Unlike a Fortran array (which the compiler tracks bounds for internally), a C pointer carries no built-in size information, so the receiving C function has no way to know how many elements are safely accessible unless told.
- iso_c_binding provides portable kind parameters (c_int, c_double, etc.) guaranteeing exact binary compatibility with C types.
- bind(c, name='...') on an interface block lets Fortran call an existing C function with a fixed, predictable symbol name.
- The value attribute is required on dummy arguments when the C function expects an argument passed by value, not by reference.
- bind(c) on a derived type declaration (or the Fortran side of a symbol) ensures the memory layout and name match exactly what C expects.
- Mixing ordinary (non-interoperable) Fortran derived types into a C interface risks silent memory-layout mismatches.
- Arrays crossing the Fortran/C boundary are passed as raw pointers plus an explicit size argument, since C has no array descriptors.
- Mixed-language projects are typically built by compiling each language separately and linking the object files together, often via CMake.
Practice what you learned
1. What problem does the iso_c_binding module primarily solve?
2. Why is the value attribute needed on a dummy argument in a bind(c) interface?
3. What must be true of a Fortran derived type that will be passed across the boundary to a C struct?
4. Why must a Fortran array passed to a C function normally be accompanied by an explicit size argument?
5. How are mixed Fortran/C projects typically built?
Was this page helpful?
You May Also Like
MPI Basics in Fortran
Get started with distributed-memory parallelism in Fortran using MPI's rank/size model, point-to-point messages, and collective operations.
Numerical Computing in Fortran
Master precision control, whole-array operations, LAPACK/BLAS integration, and floating-point pitfalls for reliable numerical Fortran code.
OpenMP in Fortran
Learn how to parallelize loops and accumulate results safely across shared-memory threads using Fortran's !$omp directives.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics