绑定C ++和Fortran [英] Binding C++ and Fortran

查看:285
本文介绍了绑定C ++和Fortran的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将C ++和Fortran结合在一起。我的Fortran代码将使用C ++函数,而C ++函数会更改Fortran的变量并将其发回。 C ++函数是用其他C ++代码构建的,例如, C ++函数将在其他.cpp文件中使用一些子函数。我使用 ifort 创建Fortran代码,并将C ++函数作为一个目标文件添加到我的Fortran生成文件中的test.o中。我还将每个需要的C ++ .o文件(支持test.o)放在makefile中。它显示错误


#6633,实际参数的类型与伪参数的类型不同。


以下是代码。



Fortran代码

  use,intrinsic :: ISO_C_BINDING,only:C_INT,C_DOUBLE 
隐式双精度(ah,oz),整数(in)
接口
整数(C_INT)函数SolveBIE_(x,y,aa,m)BIND(C,NAME ='SolveBIE_')
内部使用:: ISO_C_BINDING
隐式无
type(C_PTR),value :: x
type(C_PTR),value :: y
type(C_PTR),value :: aa
integer(C_INT),value :: m
结束函数SolveBIE_
结束接口
整数(C_INT):: m
实数(C_DOUBLE),ALLOCATABLE,DIMENSION(:, :),target :: x
(C_DOUBLE),ALLOCATABLE,DIMENSION(:, :),target :: y
real(C_DOUBLE),ALLOCATABLE,DIMENSION(:, :),target :: aa
ALLOCATE(x(0: MAXLEN,MAXINTERFACES))
ALLOCATE(y(0:MAXLEN,MAXINTERFACES))
ALLOCATE(aa(0:MAXLEN,MAXINTERFACES))

我的Fortran代码运行

  mm = SolveBIE_(x(1,1),y(1,1),aa(1,1),m)

使用C ++代码以及错误来自 x,y,aa
我使用 x(1,1)而不是 x ,因为如果使用 x ,那么还有另一个错误

$ block
6634,实际参数的形状匹配规则并且伪参数被违反了。``b $ b

我不明白为什么它应该是 x(1, 1)。为什么这是可行的,而不是 x



我的C ++代码

  #ifdef __cplusplus 
externC{
#endif
int solveBIE_(double * ini_bdry_x,double * ini_bdry_y,double * ini_bdry_um, int * fM)
{
double(* bdry_node)[2] = new double [M1] [2]; (int k = 0; k< M; k ++){
bryry_node [k + 1] [0] = ini_bdry_x [k + 1];
bdry_node [k + 1] [1] = ini_bdry_y [k + 1];
bdry_theta [k + 1] = Atan(ini_bdry_x [k + 1],ini_bdry_y [k + 1]);}

...其他.cpp文件中的一些函数


解决方案

您的界面写入的方式,您必须构建一个 C_PTR 到数组 x 并将其作为第一个参数传递:

  use,intrinsic :: ISO_C_BINDING,只有:C_INT,C_DOUBLE,C_PTR,C_LOC 
! ...
类型(C_PTR)PTRx
! ...
PTRx = C_LOC(x(LBOUND(x,1),LBOUND(x,2)))
! ...
mm = solveBIE_(PTRx,PTRy,PTRaa,m)

如图所示上面,你将不得不修复接下来的两个参数。但是你需要重写参数 fM 的接口,因为按照事实,Fortran将按值传递一个整数,而C ++期待一个指针。鉴于此,我会完全重写接口,使用C ++函数中给出的参数名称并通过引用传递所有内容。虚拟参数的名称在Fortran中可能是可见的,所以它们对于它们有意义是有用的。在下面的例子中,我假设 fM 指向被调用者的标量:

 接口
函数SolveBIE_(ini_bdry_x,ini_bdry_y,ini_bdry_um,fM)&
BIND(C,NAME ='SolveBIE_')
导入
隐式无
整型(C_INT)SolveBIE_
真(C_DOUBLE):: ini_bdry_x(*)
real(C_DOUBLE):: ini_bdry_y(*)
real(C_DOUBLE):: ini_bdry_um(*)
整数(C_INT):: fM
结束函数SolveBIE_
结束接口

然后,您可以正常或多或少地调用它作为

  mm = SolveBIE_(x,y,aa,m)

注意 x(1,1)是错误的,因为 LBOUND(x,1)= 0 ,而不是 1


I want to combine C++ and Fortran together. My Fortran code will use a C++ function and C++ function changes variables of Fortran and sends them back. The C++ function is built with other C++ codes, e.g. the C++ function will use some sub-function in other .cpp file. I make the Fortran code with ifort and I added that C++ function as one object file, test.o in my Fortran makefile. I also put every needed C++ .o file(support test.o) in makefile. It shows the error

#6633, "The type of the actual argument differs from the type of the dummy argument".

Here is the code.

Fortran code

  use, intrinsic :: ISO_C_BINDING, only: C_INT, C_DOUBLE   
  implicit double precision(a-h,o-z),integer(i-n)
  Interface
   integer (C_INT) function SolveBIE_(x, y, aa, m) BIND(C, NAME='SolveBIE_')
   use, intrinsic :: ISO_C_BINDING
   implicit none
   type (C_PTR), value :: x
   type (C_PTR), value :: y
   type (C_PTR), value :: aa
   integer (C_INT), value :: m
   end function SolveBIE_
  end Interface
  integer (C_INT) :: m
  real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: x
  real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: y
  real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: aa
  ALLOCATE(x(0:MAXLEN,MAXINTERFACES))
  ALLOCATE(y(0:MAXLEN,MAXINTERFACES))
  ALLOCATE(aa(0:MAXLEN,MAXINTERFACES))

My Fortran code run

  mm = SolveBIE_(x(1,1),y(1,1),aa(1,1),m) 

Using the C++ code and where the error is from, on x, y, aa I use x(1,1) instead of x, because if using x, then there is another error

#6634,"the shape matching rules of actual arguments and dummy arguments have been violated"`

I don't understand why it should be x(1,1). Why is this working, not x?

My C++ code

  #ifdef __cplusplus
  extern "C" {
  #endif
  int solveBIE_(double *ini_bdry_x, double *ini_bdry_y, double *ini_bdry_um, int *fM)
{  
     double(*bdry_node)[2] = new double[M1][2];
     for (int k = 0; k < M; k++) {
        bdry_node[k+1][0] = ini_bdry_x[k+1];
        bdry_node[k+1][1] = ini_bdry_y[k+1];
        bdry_theta[k+1] = Atan(ini_bdry_x[k+1], ini_bdry_y[k+1]);}

    ... some functions in other .cpp file

解决方案

The way your interface is written, you have to construct a C_PTR to array x and pass that as the first argument:

use, intrinsic :: ISO_C_BINDING, only: C_INT, C_DOUBLE, C_PTR, C_LOC
! ...
type(C_PTR) PTRx
! ...
PTRx = C_LOC(x(LBOUND(x,1),LBOUND(x,2)))
! ...
mm = solveBIE_(PTRx, PTRy, PTRaa, m)

As shown above, you would have to fix the next two arguments as well. But you need to rewrite the interface for argument fM because as matters stand, Fortran will pass an integer by value whereas C++ is expecting a pointer. Given that, I would rewrite the interface completely, using the names given for the arguments in the C++ function and passing everything by reference. Names for dummy arguments are potentially visible in Fortran, so it's useful for them to be meaningful. In the following I assume that fM points to a scalar in the callee:

  Interface
   function SolveBIE_(ini_bdry_x, ini_bdry_y, ini_bdry_um, fM) &
      BIND(C, NAME='SolveBIE_')
   import
   implicit none
   integer(C_INT) SolveBIE_
   real(C_DOUBLE) :: ini_bdry_x(*)
   real(C_DOUBLE) :: ini_bdry_y(*)
   real(C_DOUBLE) :: ini_bdry_um(*)
   integer (C_INT) :: fM
   end function SolveBIE_
  end Interface

Then later on you can invoke it more or less normally as

mm = SolveBIE_(x,y,aa,m)

Note that x(1,1) was wrong because LBOUND(x,1) = 0, not 1!

这篇关于绑定C ++和Fortran的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆