C++与Fortran动态链接库之间的数据传递

前一篇文章讨论了C++程序对Fortran动态链接库中的函数调用,其数据交换主要在Fortran程序之间,而没有出现在两种语言之间。本文进一步探讨C++与Fortran动态链接库之间的数据交换。

数据交换有多种方式,例如通过函数的参数传递、指针、全局变量等等。C++与Fortran这两种语言之间一般变量(变量或数组等)的数据传递比较容易,但自定义数据类型的数据交换则略显困难,主要是因为两种语言对于自定义数据类型的内存管理方式存在差异。示例如下:

一、Fortran90 程序

MODULE EXAMP_MOD
USE, INTRINSIC ::  ISO_C_BINDING
IMPLICIT NONE
!两个自定义类型
TYPE,BIND(C) :: EXAMP1_TYPE
   REAL(C_FLOAT)  :: A
   INTEGER(C_INT) :: I1
   INTEGER(C_INT) :: I2
END TYPE EXAMP1_TYPE

TYPE,BIND(C) :: EXAMP2_TYPE
   REAL(C_FLOAT)  :: AA
   INTEGER(C_INT) :: II1, II2
END TYPE EXAMP2_TYPE

!函数接口可以不要
!interface
!
!subroutine FSUB(EXAMP,COMMON_EXAMP,INT_ARG, STR_IN, STR_OUT) bind(C,name='FSUB')
!use examp_mod
!implicit none
!type(EXAMP1_TYPE) :: EXAMP
!type(EXAMP2_TYPE) :: COMMON_EXAMP
!INTEGER :: INT_ARG
!CHARACTER,dimension(*):: STR_IN
!CHARACTER,dimension(*) :: STR_OUT
!end subroutine FSUB
!
!end interface

END MODULE EXAMP_MOD

在Fortran中,通过module定义了两个自定义数据类型,将这两个类型定义的变量通过函数参数,实现了C++与Fortran之间的传递。

!通过参数传递这两个自定义类型的变量
SUBROUTINE FSUB(EXAMP,COMMON_EXAMP,INT_ARG, STR_IN, STR_OUT) !BIND(C,NAME='FSUB') 
!如果绑定,反而对字符参数传递有影响,因为fortran当中是字符串,而C++是字符数组
!DEC$ ATTRIBUTES DLLEXPORT::FSUB
USE EXAMP_MOD
IMPLICIT NONE

TYPE(EXAMP1_TYPE) :: EXAMP !
!DEC$ ATTRIBUTES DLLEXPORT :: vEXAMP!

TYPE(EXAMP2_TYPE) :: COMMON_EXAMP !
!DEC$ ATTRIBUTES DLLEXPORT :: vCOMMON_EXAMP!

INTEGER, INTENT(IN) :: INT_ARG !如果绑定应该使用INTEGER(C_INT)
CHARACTER(*), INTENT(IN) :: STR_IN !如果绑定应该使用CHARACTER(C_CHAR)
CHARACTER(*), INTENT(OUT) :: STR_OUT !如果绑定应该使用CHARACTER(C_CHAR)
CHARACTER*5 INT_STR
WRITE (INT_STR,'(I5.5)')INT_ARG !将整型数转换成字符串
EXAMP%A  = 12.
EXAMP%I1 = 22
EXAMP%I2 = 33
COMMON_EXAMP%AA  = 13.
COMMON_EXAMP%II1 = 24
COMMON_EXAMP%II2 = 34
STR_OUT = STR_IN // INT_STR // CHAR(0) !合并字符串,如果绑定此处STR_OUT = STR_IN
RETURN
END subroutine FSUB

二、C++程序

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <Windows.h>

// 与Fortran对应的两个自定义类型
typedef struct EXAMP1_TYPE{
    float A;
    int I1;
    int I2;
}EXAMP;

typedef struct EXAMP2_TYPE{
    float AA;
    int II1;
    int II2;
}COMMON_EXAMP;

extern "C" void _cdecl FSUB (EXAMP *vEXAMP1,          //也可使用&vEXAMP1
                      COMMON_EXAMP *vCOMMON_EXAMP1,   //也可使用&vCOMMON_EXAMP1
                               int *INT_ARG,          //也可使用&INT_ARG
                              char *STR_IN,
                              char *STR_OUT,
                            size_t  STR_IN_LEN,
                            size_t  STR_OUT_LEN);

在C++中,首先也要定义两个与Fortran对应的数据类型,同时申明外部函数,需要注意函数声明中变量的写法。

void main (int argc, char *argv[]) 
{
// declaration 
char instring[40];
char outstring[40];
int intarg;

EXAMP vEXAMP;
COMMON_EXAMP vCOMMON_EXAMP;

// initializing 

strcpy_s(instring,"Testing...");
intarg = 123;
vEXAMP.A = 0.;
vEXAMP.I1 = 0;
vEXAMP.I2 = 0;
vCOMMON_EXAMP.AA = 0.;
vCOMMON_EXAMP.II1 = 0;
vCOMMON_EXAMP.II2 = 0;

/* Call Fortran routine - pass intarg by reference,
pass length of outstring explicitly */

FSUB(&vEXAMP,&vCOMMON_EXAMP,&intarg,instring,outstring,strlen(instring),sizeof(outstring));
//若外部函数声明中使用了取地址符&,此处则应使用EXAMP,COMMON_EXAMP,intarg

printf(" %f  %i  %i  %f  %i  %i\n", vEXAMP.A, vEXAMP.I1, vEXAMP.I2, vCOMMON_EXAMP.AA, vCOMMON_EXAMP.II1, vCOMMON_EXAMP.II2);

vEXAMP.A = 0.;
vEXAMP.I1 = 0;
vEXAMP.I2 = 0;
vCOMMON_EXAMP.AA = 0.;
vCOMMON_EXAMP.II1 = 0;
vCOMMON_EXAMP.II2 = 0;

printf(" %f  %i  %i  %f  %i  %i\n", vEXAMP.A, vEXAMP.I1, vEXAMP.I2, vCOMMON_EXAMP.AA, vCOMMON_EXAMP.II1, vCOMMON_EXAMP.II2);
printf("%s\n",outstring);

system("pause");

} 

通过地址或值传递都可以实现两种语言之间的数据交换。程序运行结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值