I am working with a legacy Fortran library that requires a character scalar PATH
as an argument to the subroutine. The original interface was:
SUBROUTINE MINIMAL(VAR1, ..., PATH)
CHARACTER (LEN=4096) PATH
...
I need to be able to call this from C++ so I have made the following changes:
SUBROUTINE MINIMAL(VAR1, ..., PATH) &
BIND (C, NAME="minimal_f")
USE ISO_C_BINDING, ONLY: C_CHAR, C_NULL_CHAR
CHARACTER (KIND=C_CHAR, LEN=1), DIMENSION(4096), INTENT(IN) :: PATH
CHARACTER (LEN=4096):: new_path
! Converting C char array to Fortran CHARACTER.
new_path = " "
loop_string: do i=1, 4096
if ( PATH (i) == c_null_char ) then
exit loop_string
else
new_path (i:i) = PATH (i)
end if
end do loop_string
as per this answer. This works to convert the C-style char array to its Fortran scalar equivalent, with two problems:
- This code is on the critical path so doing the same conversion every time when the answer is the same is inefficient
- I would strongly prefer to not have to edit legacy code
I have tried:
- Just accepting a
CHARACTER (LENGTH=4096) :: new_path
directly with the ISO C binding, but I get the following compiler error:Error: Character argument 'new_path' at (1) must be length 1 because procedure 'minimal' is BIND(C)
This answer and others that I have read suggest that the ISO C binding seems to restrict what I can pass as parameters to the function, although I haven't found any official documentation yet. - This answer, which gives another algorithm to turn a C-style string into a Fortran-style equivalent in the C code and passing it to the Fortran subroutine without using the ISO C binding. (This function suggests a similar algorithm). This seems like exactly what I want but I have a linker error without the binding:
Undefined symbols for architecture x86_64:
"_minimal", referenced from:
C++-side function declaration:
extern "C" {
double minimal(int* var1, ..., const char* path);
}
This suggests that my compiler (gcc) prepends the function name with an underscore when in an extern
block. gfortran, however, does not let me name the subroutine _minimal
so the linker can't find the symbol _minimal
. (The aforementioned link suggests adding an underscore to the end of the C-side function name but this doesn't work either because of the leading underscore.)
I want to process a C-style string into a Fortran-style character scalar once in my C++ code and be able to pass it into the original interface. Any ideas?