I'm trying to call a Fortran function from C using bind(C)
with a simple dual
type that holds a value and its derivative (for forward-mode automatic differentiation).
I'm using single precision (float
in C, real(c_float)
in Fortran), and I made sure to match the struct layout.
However, when I run the program, I get a segmentation fault at runtime, even though everything compiles fine.
//main.c
#include <stdio.h>
typedef struct {
float real;
float diff;
} dual;
extern dual dual_pow_real(dual a, float b);
int main() {
dual a;
a.real = 2.0f;
a.diff = 1.0f;
dual result = dual_pow_real(a, (float) 3.00f);
//printf("result = (%f, %f)\n", result.real, result.diff);
return 0;
}
module dual_module
use iso_c_binding
implicit none
type, bind(c) :: dual
real(c_float) :: real
real(c_float) :: diff
end type dual
interface operator(**)
module procedure pow_dual_real
end interface operator(**)
contains
function pow_dual_real(a, b) result(c) bind(C, name="dual_pow_real")
type(dual), intent(in) :: a
real(c_float), intent(in) :: b
type(dual) :: c
c%real = a%real ** b
c%diff = b * (a%real ** (b - 1.0)) * a%diff
end function pow_dual_real
end module dual_module
I'm compiling with gfortran -c -fPIC
, creating a shared library, and linking with gcc -o main main.c -L. -ldual -lgfortran
.
I’ve set LD_LIBRARY_PATH=.
before running.
Both dual
structs match exactly (float
/real(c_float)
).
I tried to use double precision but got the same result.
I also tried calling the function without assigning the result, like this:
(void) dual_pow_real(a, 3.0f);
— but the segmentation fault still occurs, so the crash happens during the call itself, not when accessing the result.
I’ve tried printing debug statements — the main
function runs up to the dual_pow_real
call, then segfaults.
I tested this on both macOS with an Apple M2 (ARM64) and Ubuntu on an Intel i7 8th Gen (x86_64) — the segmentation fault occurs on both platforms, so the issue doesn't appear to be architecture-specific.
Any help will be highly appreciated.
Thank you
The function
function pow_dual_real(a, b) result(c) bind(C, name="dual_pow_real")
type(dual), intent(in) :: a
real(c_float), intent(in) :: b
expects two pointers (variables passed by reference). You are passing two scalars by value. Pass their addresses or add the value
atribute on the Fortran side to the arguments.
Either
dual_pow_real(&a, &three);
or
type(dual), value :: a
real(c_float), value :: b