Hello all,
I am having trouble interfacing structs
between Julia and Fortran. After reading around, I figured that the best way is to use iso_c_binding
and that Fortran strings are not portable (is that true?), so I went with arrays of c_char
.
I tried to define the array of chars as Ptr{UInt8}
or Vector{UInt8}
but got many segfaults, I have had more success with NTulpe{N,UInt8}
but it is still not behaving.
Below is a minimal working example:
Fortran side:
module m_struct
use,intrinsic :: iso_c_binding
implicit none
type,bind(C) :: t_struct
integer :: a
real :: b
complex :: c
logical :: d
character(C_CHAR),dimension(16) :: e
end type t_struct
contains
subroutine init_struct(struct,a,b,c,d,e) bind(C,name="init_struct")
type(t_struct), intent(inout) :: struct
integer, intent(in) :: a
real, intent(in) :: b
complex, intent(in) :: c
logical, intent(in) :: d
character(C_CHAR),dimension(16),intent(in) :: e
struct%a=a
struct%b=b
struct%c=c
struct%d=d
struct%e=e
end subroutine init_struct
subroutine print_struct(struct) bind(C,name="print_struct")
type(t_struct),intent(in) :: struct
print *,'a=',struct%a
print *,'b=',struct%b
print *,'c=',struct%c
print *,'d=',struct%d
print *,'e=',struct%e
end subroutine print_struct
end module m_struct
Julia side:
const structlib="./libstruct_iso_c.so"
const init_struct=(:init_struct,structlib)
const print_struct=(:print_struct,structlib)
mutable struct j2f_struct
a::Int32
b::Float32
c::Complex64
d::Bool
e::NTuple{16,UInt8}
end
julia> aa=(ntuple(i->convert(UInt8,' '),16))
(0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20)
julia> bb=map(i->convert(UInt8,i),('h','e','l','l','o'))
(0x68, 0x65, 0x6c, 0x6c, 0x6f)
julia> bb=(bb...,ntuple(i->convert(UInt8,' '),11)...)
(0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20)
julia> my_jstruct= j2f_struct(0,0,0,false,aa);
julia> my_jstruct2= j2f_struct(0,0,0,false,bb);
julia> ccall(print_struct,Void,(Ptr{j2f_struct},),Ref(my_jstruct))
a= 0
b= 0.0000000E+00
c= (0.0000000E+00,0.0000000E+00)
d= F
e=
julia> ccall(print_struct,Void,(Ptr{j2f_struct},),Ref(my_jstruct2))
a= 0
b= 0.0000000E+00
c= (0.0000000E+00,0.0000000E+00)
d= F
e=lo ## NOTE MISSING 3 CHARACTERS
ccall(init_struct,Void,(Ref{j2f_struct},Ref{Int32},Ref{Float32},Ref{Complex64},Ref{Bool},Ref{NTuple{16,UInt8}}),Ref(my_jstruct),1,2.,3.2+5.*im,true,Ref(bb))
julia> ccall(print_struct,Void,(Ptr{j2f_struct},),Ref(my_jstruct))
a= 1
b= 2.000000
c= (3.200000,5.000000)
d= T
e=hello #PRINTS FINE
my_jstruct.e
(0x2b, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20)
bb
(0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20)
Can someone explain to me what is happening with the first 3 characters, or how to fix this? More generally, what is the way to interface with Fortran strings.
Thank you for your assistance