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(*)再加入字符长度,这样可以保证任意长度的字符串

posted @ 2022-03-21 14:05  小船1968  阅读(338)  评论(0编辑  收藏  举报