Integrating C Libraries in Fortran using ISO_C_BINDING
Learn how to use the ISO_C_BINDING module to call C functions from Fortran, ensuring type safety and avoiding name mangling issues in cross-language engineering.
05 Feb 2026, 00:35 UTC

The Challenge of Cross-Language Interoperability
When integrating legacy C libraries or system-level APIs into a Fortran application, the primary obstacle is the difference in how each language handles data types, memory alignment, and symbol naming (name mangling). Without a standardized interface, developers often rely on compiler-specific flags or fragile naming conventions to link the two languages.
The ISO_C_BINDING module, introduced in Fortran 2003, solves this by providing a set of portable types and attributes that force the Fortran compiler to use C-compatible calling conventions and data layouts. The key takeaway is that by using BIND(C) and the iso_c_binding constants, you eliminate the need for language-specific wrappers and ensure the linker can resolve symbols across different compilers.
How ISO_C_BINDING Works
The module provides two critical components: kinds and attributes. Kinds (such as C_INT or C_DOUBLE) ensure that the bit-width of a Fortran variable matches the C int or double on the target architecture. Attributes, specifically BIND(C), instruct the compiler to disable name mangling—the process where compilers add underscores or suffixes to function names—and use the C ABI (Application Binary Interface).
Implementation Example: Calling a C Function from Fortran
Consider a scenario where you have a C function that calculates a weighted sum, and you need to call it from a Fortran simulation loop.
C Source (math_utils.c):
#include <stdio.h>
// A simple C function to be called by Fortran
void compute_sum(int n, double *values, double *result) {
double sum = 0.0;
for (int i = 0; i < n; i++) {
sum += values[i];
}
*result = sum;
}
Fortran Source (main.f90):
program call_c_example
use iso_c_binding
implicit none
! Define the interface to the C function
interface
subroutine compute_sum(n, values, result) bind(C, name='compute_sum')
import :: C_INT, C_DOUBLE
integer(C_INT), value :: n
real(C_DOUBLE), dimension(*) :: values
real(C_DOUBLE), intent(out) :: result
end subroutine compute_sum
end interface
integer(C_INT) :: num_elements = 3
real(C_DOUBLE) :: data_array(3) = [1.1_C_DOUBLE, 2.2_C_DOUBLE, 3.3_C_DOUBLE]
real(C_DOUBLE) :: total_sum
call compute_sum(num_elements, data_array, total_sum)
print *, "The sum is: ", total_sum
end program call_c_example
Critical Configuration Details
- The
valueattribute: In the example above,nis marked asvalue. By default, Fortran passes arguments by reference (pointers). Since the C function expects anintand not anint*, thevalueattribute is required to pass the actual integer. - The
importstatement: This allows the interface block to use the constants defined in theiso_c_bindingmodule without needing ausestatement inside the interface itself. - Array Handling: Fortran arrays are passed as pointers to the first element, which matches C's array handling.
Limitations and Common Pitfalls
While ISO_C_BINDING simplifies integration, it does not automate memory management or complex type mapping.
Type Mismatches and Padding
A common mistake is using standard Fortran integer or real instead of the C_INT or C_DOUBLE kinds. On some platforms, a default Fortran integer might be 32-bit while a C long is 64-bit, leading to stack corruption. When using derived types (structs), you must ensure the Fortran type, bind(C) matches the C struct layout exactly, including padding. Any mismatch in the order or size of members will result in the Fortran program reading the wrong memory addresses.
Pointer Lifetime and Ownership
When using C_PTR (a Fortran type that represents a C pointer), ownership is not tracked. If a C function allocates memory using malloc() and returns a C_PTR to Fortran, Fortran cannot free that memory using its own internal mechanisms. You must either provide a C function to free the memory or use a C-compatible deallocator to avoid memory leaks.
Verification and Compilation
To verify the binding, you must compile both components and link them together. Using gfortran and gcc:
- Compile the C code:
gcc -c math_utils.c -o math_utils.o - Compile the Fortran code:
gfortran -c main.f90 -o main.o - Link the objects:
gfortran main.o math_utils.o -o simulation_app
Check: Run ./simulation_app. If the binding is incorrect (e.g., missing BIND(C)), the linker will likely throw an "undefined reference" error because it is searching for a mangled name like compute_sum_ instead of the exact C symbol compute_sum.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.