如何在C++数据结构中存储Fortran风格长字符标量并调用遗留Fortran库接口
可行解决方案
方案1:新增独立Fortran包装层(零修改原有遗留代码,性能最优)
完全不触碰原有遗留Fortran库的代码,单独编写一个Fortran包装文件,通过ISO C绑定暴露C可调用接口,内部直接调用原有子例程:
! 独立文件:fortran_wrapper.f90,无需修改原有遗留代码 SUBROUTINE minimal_wrapper(VAR1, ..., path_c) BIND(C, NAME="minimal_wrapper") USE ISO_C_BINDING, ONLY: C_CHAR, C_INT ! C侧传入的预填充4096字节char数组 CHARACTER(KIND=C_CHAR, LEN=1), DIMENSION(4096), INTENT(IN) :: path_c INTEGER(C_INT), INTENT(INOUT) :: VAR1 ! 声明原有遗留子例程的接口 INTERFACE SUBROUTINE MINIMAL(VAR1, ..., PATH) INTEGER, INTENT(INOUT) :: VAR1 CHARACTER(LEN=4096), INTENT(IN) :: PATH END SUBROUTINE MINIMAL END INTERFACE CHARACTER(LEN=4096) :: path_f ! 直接内存拷贝,无循环转换开销 path_f = TRANSFER(path_c, path_f) ! 调用原有遗留子例程 CALL MINIMAL(VAR1, ..., path_f) END SUBROUTINE minimal_wrapper
C++侧只需一次性将C风格字符串转换为4096长度、剩余位置补空格、无null终止符的字符数组,后续每次调用直接传入该数组即可,无运行时转换开销:
// C++侧字符串预转换逻辑,仅执行一次 char fortran_path[4096]; memset(fortran_path, ' ', 4096); memcpy(fortran_path, your_c_str, std::min(strlen(your_c_str), (size_t)4096)); // 声明包装函数 extern "C" { void minimal_wrapper(int* var1, ..., const char* path_c); } // 调用示例,直接传入预转换好的数组 minimal_wrapper(&var1, ..., fortran_path);
方案2:直接调用原有Fortran子例程
解决符号匹配和隐式参数问题即可正常调用,无需编写任何Fortran代码:
- 首先查看遗留库中MINIMAL子例程的实际符号名:
使用nm libyour_fortran_lib.a | grep -i minimal命令查看符号,x86_64 Linux下gfortran默认生成minimal_,macOS下默认生成_minimal_。 - C++侧声明对应符号,同时补充Fortran字符参数的隐式长度参数(Fortran默认会在所有参数末尾追加字符参数的长度,类型为
size_t):
// Linux下示例,符号为minimal_ extern "C" { double minimal_(int* var1, ..., const char* path, size_t path_len); } // 调用示例,传入预转换好的4096长度数组,最后补充长度参数4096 minimal_(&var1, ..., preprocessed_fortran_path, 4096);
如果需要跨平台兼容,可以通过编译宏自动匹配不同平台的符号规则。
方案3:修改编译参数对齐符号规则
给gfortran增加编译参数-fno-underscoring,关闭默认的下划线修饰,生成的符号名和原子例程名完全一致(小写),直接和C++侧extern "C"声明的minimal匹配即可,注意所有Fortran代码需要用相同参数编译。
内容的提问来源于stack exchange,提问作者Sebastian Wieczorek
相关产品推荐
相关产品推荐

