I have a list of fixed size strings (character*6) that I want to give to a c function. To be fully interoperable between Fortran and C I must use an array of single characters. But how do I assign a character*6 that I have to this array? The code below works except for this character*6 to character(len=1) var(6) issue.
type, bind(C) :: RelayElement
integer (kind=C_INT) :: lzop_tag
integer (kind=C_INT) :: relay_tag
character (kind=C_CHAR) :: codes(6)
character (kind=C_CHAR) :: desigs(21)
character (kind=C_CHAR) :: zuns(2)
end type RelayElement
character(len=6) :: new_codes
type (RelayElement) :: element
subroutine c_interop(element) bind(C)
type(RelayElement) :: element
end subroutine c_interop
new_codes = 'codea'
!below, it is a pain to assign codes as an array, hard to maintain and read
element = RelayElement(lzop_tag=1,relay_tag=2, codes=['c','o','d','e','s',C_NULL_CHAR],desigs='desigs',zuns='a')
element%codes = new_codes ! this is what I need. I have the codes in fortran and need to give it to c. Does not work
! element%codes is now just the first character of new_codes repeated
call c_interop(element) ! this works except for the issue above.
I can get it to work by assigning the Fortran string (Character*6) to the Fortran character array in a loop:
DO i = 1,SIZE(element%codes)
element%codes(i:i) = new_codes(i:i)
It works but it seems very busy. I can't find another way.
In other parts of my Fortran 77 code, it uses
interface to subroutine c_interop
character*6 carray [reference]
If you need NUL-termination, you have to put it there explicitly:
new_codes = 'codea'//C_NULL_CHAR
Given that, the natural way to copy raw data from one variable to another is via TRANSFER:
element%codes = TRANSFER(new_codes,element%codes,SIZE(element%codes))
In this expression, if LEN(new_codes) > SIZE(element%codes), only the first SIZE(element%codes) characters will be copied. If LEN(new_codes) < SIZE(element%codes), all of new_codes will be copied with garbage following to pad out to SIZE(element%codes). Assuming the C code uses NUL-termination, that extra garbage will not be a problem. Remember that LEN(new_codes) is the declared length of the variable, not the length of what you usefully assigned to it (normally that would be LEN_TRIM(new_codes)).
Be careful about NUL termination when the size of codes is less than the length of the source if it is always expected on the C side Or you can do something like the following:
new_codes = .. ! No null ternination here asc: associate( lenm => min(size(element%codes), len_trim(newcode)+1) ) element%codes(1:lenm-1) = transfer( new_codes, mold=element%codes, size=lenm-1 ) element%codes(lenm:lenm) = c_null_char end associate asc