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)?

francescalus
  • 30,576
  • 16
  • 61
  • 96
gspr
  • 11,144
  • 3
  • 41
  • 74
  • 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? – francescalus Aug 27 '21 at 09: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? – Ian Bush Aug 27 '21 at 09: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? :-) – gspr Aug 27 '21 at 09: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! – gspr Aug 27 '21 at 09:32
  • Given `logical(c_bool) c_l(10); logical c(10)` then `c_l=c` copies the array `c` to `c_l`, changing the kind parameter in the process if necessary. That's what you want, isn't it? For the character there's more required, but if you copy to an array then you can pass that array copy to the scalar argument. (If this is what you want then we can find duplicates for you.) – francescalus Aug 27 '21 at 09:43
  • @francescalus: D'oh, this just goes to show little Fortran I know. I imagined that that would just copy the pointer to the underlying memory. But you're telling me it does a deep copy with type conversion? If that's the case, then yes, that's what I want, and my question is indeed surely a duplicate :-) – gspr Aug 27 '21 at 09:46
  • 2
    Yes, nothing in the Fortran side is a pointer. – francescalus Aug 27 '21 at 09:47
  • Sorry for the noise. I think this question is best closed as a duplicate pointing to a question about basic copying of arrays in Fortran. – gspr Aug 27 '21 at 11:00
  • Maybe a duplicate won't suffice. There are two distinct aspects. The first one, changing kind parameter, is easy to address, but there's also commentary to be had on whether the conversion would actually be necessary. Instead of dup-closing I've stitched the two together in an answer here. Let's see what others think. – francescalus Aug 27 '21 at 11:31
  • I've assumed `logical(10) l` is just a mistake in creating the example, rather than actually being correct. If it is meant to be `logical(10) l` (a scalar not an array, and not valid in F77) then please roll back and we can address that mistake also. – francescalus Aug 27 '21 at 11:48

1 Answers1

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
francescalus
  • 30,576
  • 16
  • 61
  • 96