I am trying to pass a struct from Python to Fortran as follows
import ctypes as ct
import numpy as np
from numpy.ctypeslib import ndpointer
# import the shared library
fortlib = ct.CDLL('./pass_struct.so')
f = fortlib.pass_struct
class TestStruct(ct.Structure):
_fields_ = [("n_nonzeros", ct.c_int),
("values", ct.POINTER(ct.c_double)),
("nonzeros", ct.POINTER(ct.c_int))]
# Specify arguments type as a pointer to double and an integer
f.argtypes=[ct.POINTER(TestStruct)]
# Create a double array, pass it to Fotran as a pointer
values = np.ones((3), dtype=np.float_, order="F")
values[0] = 1.
values[1] = 2.
values[2] = 3.
values_ptr = values.ctypes.data_as(ct.POINTER(ct.c_double))
nonzeros = np.ones((3), dtype=np.intc, order="F")
nonzeros[0] = 1
nonzeros[1] = 2
nonzeros[2] = 3
nonzeros_ptr = nonzeros.ctypes.data_as(ct.POINTER(ct.c_int))
print("values", values)
print("nonzeros", nonzeros)
test_struct = TestStruct(ct.c_int(3), values_ptr, nonzeros_ptr)
# Call function
f(ct.byref(test_struct))
subroutine pass_struct(st) bind(C, name="pass_struct")
use iso_c_binding
implicit none
type, bind(c) :: test_struct
integer(c_int) :: n_nonzeros
type(c_ptr) :: values
type(c_ptr) :: nonzeros
end type
type(test_struct), intent(in) :: st
real(c_float), pointer :: c_values(:)
integer(c_int), pointer :: c_nonzeros(:)
print *, "test", st%n_nonzeros
call c_f_pointer(st % values, c_values, [st%n_nonzeros])
call c_f_pointer(st % nonzeros, c_nonzeros, [st%n_nonzeros])
print *, "values fortran", c_values
print *, "nonzeros fortran", c_nonzeros
end subroutine pass_struct
Output
values [1. 2. 3.]
nonzeros [1 2 3]
test 3
values fortran 0.00000000 1.87500000 0.00000000
nonzeros fortran 1 2 3
Otherwise looks fine, but “values fortran”. Do I have a mistake in the code?
edit.
code is compiled with
gfortran -shared pass_struct.f90 -o pass_struct.so