I know that the topic of string passing has been discussed a lot, but mostly from C++ or C to Fortran, not the other way around. I have not seen the approach below so I want to present it here for discussion. The advantage is that regular Fortran functions can be used unmodified (except for the bind(C)
and kind=C_CHAR
, which does not really change anything).
Fortran code to be called from C++ or C:
module p
use, intrinsic :: ISO_C_binding
implicit none
contains
subroutine IO_printCppString(f_str) bind(C, name="F_IO_printCppString")
character(kind=C_CHAR,len=*), intent(in) :: f_str
write (*, '(a)') f_str
end subroutine IO_printCppString
end module p
C++ code:
#include <ISO_Fortran_binding.h>
#include <iostream>
extern "C" {
void F_IO_printCppString(CFI_cdesc_t* f_str);
}
int main() {
std::string hello = "Hello World";
CFI_cdesc_t f_string;
f_string.base_addr = (void*)const_cast<char*>(hello.c_str()); // void* cast needed? //
f_string.elem_len = hello.length();
f_string.rank = (CFI_rank_t)0; // or 1 ? and what about CFI_dim_t in that case //
f_string.version = CFI_VERSION;
f_string.type = CFI_type_char;
f_string.attribute = CFI_attribute_other; // correct? //
F_IO_printCppString(&f_string);
return 0;
}
I works fine with gfortran/g++ and ifx/icpx, but when checking with valgrind Intel is not 100% fine. Note that the number of lost bytes does not depend on the string length.
To run
#! /usr/bin/env bash
rm -rf hello p.o hello.o
gfortran -Og -g -fsanitize=undefined -c p.f90
g++ -Og -g -fsanitize=undefined -c hello.cpp
gfortran -fsanitize=undefined p.o hello.o -o hello -lstdc++
valgrind --leak-check=full --show-leak-kinds=all ./hello
rm -rf hello p.o hello.o
ifx -traceback -O0 -c p.f90
icpx -traceback -O0 -c hello.cpp
icpx p.o hello.o -o hello -fortlib
valgrind --leak-check=full --show-leak-kinds=all ./hello