Diagnosing BIND(C) Interoperability Failures: A Step‑by‑Step Fortran Guide
Diagnose and fix Fortran BIND(C) interoperability failures with a clear step‑by‑step guide: check symbol names, argument types, compiler flags, ABI compatibility, and use a minimal test case to verify the link and runtime behavior.
11 Jun 2026, 04:18 UTC

Problem Statement
When a Fortran program calls a C function via BIND(C), the most common failure is a link‑time unresolved symbol or a runtime crash due to a mismatched calling convention. This guide walks through the recognizable symptoms, the root causes, and a sequence of checks that will help you pinpoint and fix the problem.
Recognizable Condition
- Linker error:
undefined reference to `external_func'or similar. - Runtime crash after the first call (segmentation fault, illegal instruction).
- Wrong return value or corrupted arguments.
Diagnostic Table
| Symptom | Likely Cause | Immediate Check |
|---|---|---|
| Unresolved symbol at link time | Incorrect symbol name or mangling | Verify BIND(C, name='…') matches the C function’s exported name |
| Runtime crash or corrupted data | Argument type mismatch or calling convention clash | Check argument kinds and order, ensure iso_c_binding is used |
| Wrong return value | Return type mismatch or ABI difference | Confirm return kind and that both compilers use the same ABI (e.g., System V AMD64) |
| Build succeeds but program hangs | Optimiser interfering with C calling convention | Compile with flags that disable sibling‑calling optimisations |
| Linker finds symbol but program crashes immediately | ABI mismatch between C and Fortran compiler | Check compiler versions and ABI compatibility notes |
Ordered Checks & Fixes
- Confirm
BIND(C)Declaration- In Fortran, the subroutine or function must be declared with
BIND(C)and an explicitnameattribute if the C symbol differs.interface function add(a, b) bind(C, name='add') result(res) import :: C_INT integer(C_INT), value :: a, b integer(C_INT) :: res end function add end interface - In C, the function must be declared without name mangling:
extern "C" int add(int a, int b);
- In Fortran, the subroutine or function must be declared with
- Verify Argument Types
- Fortran
integer(C_INT)maps tointin C. If you useinteger(C_LONG), it maps tolong. - Use
valueattribute in Fortran to pass by value, matching C’s default. - For
real(C_DOUBLE), C expectsdouble. - For
character(kind=C_CHAR), C expectschar.
- Fortran
- Check Name Mangling
- Run
nmon the C object to see the exported symbol.nm add.o | grep add - Ensure the Fortran compiler is not appending underscores or changing case. If you need a specific name, use
bind(C, name='add').
- Run
- Compiler Flags for Calling Convention
- Some optimisers (e.g., GCC’s sibling‑calling optimisation) can change the stack layout. Disable it with
-fno-optimize-sibling-calling. - Example compile command for GCC/Intel:
gfortran -c -fno-optimize-sibling-calling test.f90 gcc -c add.c gfortran test.o add.o -o test
- Some optimisers (e.g., GCC’s sibling‑calling optimisation) can change the stack layout. Disable it with
- ABI Compatibility
- Both compilers must target the same Application Binary Interface (ABI). On Linux x86‑64, System V AMD64 is standard.
- Check compiler docs for ABI flags (e.g.,
--abi=32for 32‑bit).
- Minimal Test Case
- Create a tiny C file:
/* add.c */ #include <stdio.h> int add(int a, int b) { return a + b; } - And a Fortran file:
program test use iso_c_binding interface function add(a, b) bind(C, name='add') result(res) import :: C_INT integer(C_INT), value :: a, b integer(C_INT) :: res end function add end interface print *, add(2, 3) end program test - Compile and link:
gfortran -c test.f90 gcc -c add.c gfortran test.o add.o -o test ./test # Expected output: 5 - If the output is not 5 or you get a crash, revisit the checks above.
- Create a tiny C file:
- Escalation Criteria
- If all checks pass but the program still crashes, suspect an ABI mismatch between the C and Fortran compilers. Try compiling both with the same vendor (e.g., GCC for both) or consult the vendor’s interoperability guide.
- For large projects, enable debug symbols (
-g) and usegdbto step into the C function to see where the stack or registers are corrupted. - If the issue persists across multiple C functions, consider using a wrapper that isolates Fortran and C, or switch to a language that guarantees ABI compatibility (e.g., C++ with extern "C").
Limitations & Practical Checks
- Different Fortran compilers (Gfortran, Intel, PGI) may have subtle differences in default integer kind. Always query
integer(C_INT)size withprint *, c_int_sizeof(). - Some systems use a 64‑bit
intin C; if your Fortran code usesinteger(C_INT)assuming 32‑bit, data will be truncated. - Always verify the final binary with
objdump -tornmto ensure the symbol names match. - When using libraries, check that the library’s ABI is documented and that you compile with matching flags.
Conclusion
By following the ordered checks above, you can systematically identify the root cause of a BIND(C) interoperability failure. The key is to ensure that symbol names, argument types, and calling conventions line up exactly between Fortran and C, and that both compilers target the same ABI. A minimal test case is an invaluable sanity check before scaling up to larger projects.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.