windows下fortran 与C++混合编程的探索
百度后,找到相关资源,最好的一篇是:https://www.cnblogs.com/ljwan1222/p/9546244.html
我的环境如下: windows下 VS环境,IVF环境
例1: 基本的结构
1. C++ 动态库结构
(1)头文件
#ifdef __cplusplus extern "C" { #endif extern void __stdcall MOMENT_NEW(int* a); //子过程, 没有__stdcall前缀也可以 extern int __stdcall AFUNC(); //函数, 没有__stdcall前缀也可以 extern double __stdcall BFUNC(bool); //#define moment_new MOMENT_NEW //将函数名改为小写,使用define转为大写,失败 //#define afunc AFUNC //#define bfunc BFUNC #ifdef __cplusplus } #endif #endif //F_LIB_H
(2)cpp文件
// moment.cpp void MOMENT_NEW(int* a) { a++; } int AFUNC() { return 10; } double BFUNC(bool a) { return 3; }
(3)def文件
LIBRARY f_lib EXPORTS MOMENT_NEW @1 AFUNC @2 BFUNC @3
2. fortran 主程序结构
program main use iso_c_binding !这个根据资料是必要的,通过试验,可能不需要 implicit none type(c_ptr) :: foo interface f_lib1 !用一个interface引入C++库的相关内容,名称可以任意 subroutine MOMENT_NEW(a) !函数名必须相同,包括参数类型要对应 implicit none integer::a !声明参数类型 end subroutine MOMENT_NEW integer(4) function AFUNC() implicit none end function AFUNC real(8) function BFUNC(c) implicit none logical::c end function BFUNC ! type(c_ptr) :: a end interface f_lib1 integer(4) jd real(8) js call MOMENT_NEW(4) jd = AFUNC() js = BFUNC(.TRUE.) write(*,*) jd, js end
例2: 使用字符串
1. C++ 动态库结构
(1)头文件
extern double __stdcall BFUNC(char* str);
(2)实现
double BFUNC(char* str) { cout << str << endl; return 0.; }
2. fortran主程序
real(8) function BFUNC(str) implicit none character(100)::str !fortran中的字符串大小是固定的 end function BFUNC ! type(c_ptr) :: a end interface f_lib1 integer(4) jd real(8) js character(100)::str; call MOMENT_NEW(4) jd = AFUNC() str = 'I can do it'; js = BFUNC(str) write(*,*) jd, js
例3: 使用回调
1. C++动态库
(1)头文件
#pragma once #ifdef __cplusplus extern "C" { #endif extern void __stdcall INITMQ(void* callback, double* time); extern void __stdcall SEND_REPORT(int* type, char* data, double* time); #ifdef __cplusplus } #endif
(2)cpp文件
文件中,pf函数作为参数输入
// MidWare.cpp : 定义 DLL 应用程序的导出函数。 // #include "MidWare.h" #include <iostream> using namespace std; typedef int(*pf)(int* type, char* data, int* len, double* time);
pf mycb; void INITMQ(void* callback, double* time) { pf mycb = (pf)callback; int t = 10; char mdata[] = "data parameter"; //double time = 0.; int len = strlen(mdata); p(&t, mdata, &len, time); cout << "initmq" << endl; } void SEND_REPORT(int* type, char* data, double* time) { cout << "SEND_REPORT" << endl; cout << data << endl; cout << *time << endl; }
2. fortran主程序
(1) message_ware模块
MODULE MESSAGE_WARE use iso_c_binding implicit none interface midware subroutine INITMQ(callback, ntime) implicit none interface subroutine callback(cmd, dat, dlen, time) !回调处理 integer::cmd character::dat(100) real(8)::time integer::dlen end subroutine callback end interface real(8)::ntime end subroutine INITMQ subroutine SEND_REPORT(data_type, mdata, time) implicit none integer::data_type character::mdata(100) real(8)::time end subroutine SEND_REPORT end interface midware contains subroutine mcallback(cmd, dat, dlen, time) integer::cmd character::dat(100) real(8)::time integer::dlen print *, cmd !slen = LEN(dat) print *, dat(1:dlen) !print *, dat end subroutine mcallback END MODULE MESSAGE_WARE
(2)主程序
program MidWareServer use iso_c_binding use MESSAGE_WARE implicit none ! Variables type(c_ptr) :: a real(8)::time = 0. character(100)::id = 'dasdf' character,allocatable,dimension(:)::sdata logical::bool ! Body of MidWareServer allocate(sdata(120)); sdata = 'ddddd' CALL INITMQ(mcallback, time) CALL SEND_REPORT(1, sdata, time) !CALL GET_REQUEST(bool, id, sdata, 2); print *, 'Hello World' end program MidWareServer
新的发现是:
(1)当字符串为参数时,需要将charater(100):: a 改为 charater::a(100), 在回调中才能使用
(2)C++库中的字符串参数为char* 类型,fortran中参数可以使用可变长字符数组作为实参,如上面的例子中,使用了超过100长度的变长数组sdata,可以完成数据传递
(3)fortran回调函数必须在参数中指出字符串的长度,否则无法知道字符串中有多少有效字符
(4)回调和接口中最好使用不定长字符数组 charater::a(*)再加入字符长度,这样可以保证任意长度的字符串