Fortran to Julia structs with strings


#1

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 :slight_smile:


#2

I think it’s because Julia’s Bool isn’t the same size as Fortran’s logical. Check out sizeof(Bool) in Julia. I think you want to use the type Cint instead.


#3

Thank you, that solves it!

When I had tested the Bool without the char array it was the last field, so it “behaved correctly” though it was wrong.