3

I am wrapping some legacy F77 code (that I cannot alter) in a C interface. Suppose the legacy code has

subroutine foo(s, l)
  character*10  s
  logical       l(10)
  …

I'm writing a small F2008 wrapper foo_wrapper that intends to expose a C-compatible interface through ISO_C_BINDING, do any necessary type conversions, call foo, and finally type-convert back again. My understanding is that I should start out with

subroutine foo_wrapper(c_s, c_l) bind(C, name="foo_wrapper")
  use ISO_C_BINDING, only: C_CHAR, C_BOOL
  character(kind=C_CHAR, len=1), dimension(10) :: c_s
  logical(kind=C_BOOL)                            c_l(10)
  …

but how do I actually do the conversion from c_s into a character*10, and likewise for c_l into a logical (and back after the call)?

10
  • For the logical, are you asking about simply changing kind type parameter (like l=logical(c_l); ...; c_l=logical(l, kind=c_bool)) or is it something else? Commented Aug 27, 2021 at 9:20
  • 1
    I'm struggling to see the problem, can't you just copy in to variables of the appropriate types and kinds and back out again? Commented Aug 27, 2021 at 9:20
  • @IanBush: Copy the underlying memory? No, I don't have any guarantees that c_s has the same memory representation as the first argument to foo (and likewise for c_l and the second argument). Copy each element in a loop with type conversion? Yes, that's exactly what I wanna do. How? :-) Commented Aug 27, 2021 at 9:32
  • @francescalus: I'm not sure I understand your question, can you elaborate? Thanks for the edit, by the way – it improved the title a lot! Commented Aug 27, 2021 at 9:32
  • 2
    Yes, nothing in the Fortran side is a pointer. Commented Aug 27, 2021 at 9:47

1 Answer 1

5

Types with default kind parameters do not necessarily fail to be interoperable. Interoperability is based on the kind number, not the specific use of kind=c_kind, in the declaration. If the kind numbers (and if they have them, the length type parameters) match then the types are the same.

Intrinsic assignment to a variable of intrinsic type of an expression of the same intrinsic type "converts" the kind type parameter as necessary.

A copy-in/copy-out mechanism would be like

<type>(kind=f_kind) f
<type>(kind=c_kind) c

c = f
call foo(c)
f = c

where f and c can also be arrays of the same shape as each other.

This always copies. If you want to be more fancy, you can use the techniques in an answer to a related question, using pointers, to copy only if the default and interoperable kinds are not the same.

For real and integer intrinsic types, one may expect default kind parameters (or double precision for the real(kind=c_double)) to be the interoperable ones. Default logical is less likely to be interoperable: Fortran's default logical has the same storage size as default real which probably won't be what C's boolean type has.

Characters also naturally may have interoperable default kind, but you also have to worry about the conversion between the scalar and the array. Again, the technique in the copy/associate linked answer handle this at the same time as the kind conversion.

Consider the program

  use, intrinsic :: iso_c_binding
  implicit none
  
  print 1, "float", KIND(0e0)==c_float
  print 1, "double", KIND(0d0)==c_double
  print 1, "int", KIND(1)==c_int
  print 1, "char", KIND('')==c_char
  print 1, "bool", KIND(.TRUE.)==c_bool

1 format (A,":",T10,L1)
end program
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.