从C调用返回Fortran函数的数组

从C调用返回Fortran函数的数组,c,arrays,module,fortran,C,Arrays,Module,Fortran,我有一个已经存在的Fortran源代码,我正在将C添加到其中,并且很难将一个数组从C传递到Fortran函数中,然后再接收另一个数组 它编译时没有任何错误,但当我尝试运行代码时,它会说: 数组“p2”(在Fortran函数中)的维数具有范围3,而不是-4537421815(或其他类似数字) 我不知道这里发生了什么事。我将附上下面的两个代码 注意:我已经删除了很多额外的变量初始化行,我认为这对于发现问题似乎是不必要的 C功能: #include <stdio.h> #include &

我有一个已经存在的Fortran源代码,我正在将C添加到其中,并且很难将一个数组从C传递到Fortran函数中,然后再接收另一个数组

它编译时没有任何错误,但当我尝试运行代码时,它会说:

数组“p2”(在Fortran函数中)的维数具有范围3,而不是-4537421815(或其他类似数字)

我不知道这里发生了什么事。我将附上下面的两个代码

注意:我已经删除了很多额外的变量初始化行,我认为这对于发现问题似乎是不必要的

C功能:

#include <stdio.h>
#include <stdlib.h>    

extern "C" double* __multiphase_tools_MOD_project(double p1[],double *mydt,int *myi,int *myj,int *myk);

extern "C" void cuda_(int *ptr_band, double *ptr_u, double *ptr_v, double *ptr_w)
{

     double *pt_out;
     double pt_in[3];


     // Loop over the domain and compute fluxes near interfaces
     //=======================================================================================
     //  X FACE
     //=======================================================================================

     for (k = kmin; k <= kmax; k++)
     {
          for (j = jmin; j <= jmax; j++)
          {
               for (i = imin; i <= imax; i++)
               {
                    if (abs(band[i-1][j][k]) <= nband_CFL && abs(band[i][j][k]) <= nband_CFL )
                    {
                         for (int n = 1; n < 10; n++)
                         {
                              pt_in[0] = pt[0][n][1];   pt_in[1] = pt[1][n][1];  pt_in[2] = pt[2][n][1];
                              pt_out = __multiphase_tools_MOD_project(pt_in,&neg_dt_uvw,&i,&j,&k);
                         }
                    }
               }
          }
     }
     return;
}

返回数组的Fortran函数实际上使用隐藏参数,其实现方式与子例程类似。这就是为什么您不能轻松地编写兼容的C函数,因为您无法以可移植的方式确定隐藏的参数属性

比如说

function f() result(res)
  real :: res(3)
  res = [1.,2.,3.]
end
在GCC内部代码中查找为

f (struct array1_real(kind=4) & __result)
{
}
我建议把这个函数转换成一个子程序。这样,您就可以精确地控制数组的参数,并创建一个C接口:

  subroutine project(p1,p2,mydt,myi,myj,myk) bind(C)
    real(WP), dimension(3), intent(out):: p2
    ...

或者您可以编写一个包装子例程来调用您的函数,以保持Fortran功能不变。

返回数组的Fortran函数实际上使用隐藏参数,实现方式与子例程类似。这就是为什么您不能轻松地编写兼容的C函数,因为您无法以可移植的方式确定隐藏的参数属性

比如说

function f() result(res)
  real :: res(3)
  res = [1.,2.,3.]
end
在GCC内部代码中查找为

f (struct array1_real(kind=4) & __result)
{
}
我建议把这个函数转换成一个子程序。这样,您就可以精确地控制数组的参数,并创建一个C接口:

  subroutine project(p1,p2,mydt,myi,myj,myk) bind(C)
    real(WP), dimension(3), intent(out):: p2
    ...

或者您可以编写一个包装子例程来调用您的函数,以保持Fortran功能不变。

为什么不在Fortran函数定义中添加
bind(c)
,并避免(我认为是)手动名称损坏?这也可以解决通话问题。我刚刚注意到:为什么要使用
iso_c_绑定
,而不引用其中的任何实体?这个模块可能没有你想象的那样做。尝试向fortran函数中添加bind(C),它说返回类型不能是数组。这是关于返回数组的一个非常好的观点(我错过了)。但问题的潜在根源是:Fortran数组与C数组不同。也许您可以重新编写函数以返回一个C指针,但这确实会打乱您的其他Fortran调用。[我现在不多说了,因为我显然只是在猜测。]如果您将p2(:)作为伪参数接收到project()的包装器(这样包装器是C-可互操作的),那么我想没有必要用C重新编写project()。根据代码库的大小,我的建议可能不可行。但是,为什么不让函数返回一个
类型(c_ptr)
然后使用
调用c_f_指针(c_loc(old_c_ptr),fortran_ptr)
来确保正确的c语言样式转换。为什么不将
绑定(c)
添加到fortran函数定义中并避免(我假设是)手动名称更改?这也可以解决通话问题。我刚刚注意到:为什么要使用
iso_c_绑定
,而不引用其中的任何实体?这个模块可能没有你想象的那样做。尝试向fortran函数中添加bind(C),它说返回类型不能是数组。这是关于返回数组的一个非常好的观点(我错过了)。但问题的潜在根源是:Fortran数组与C数组不同。也许您可以重新编写函数以返回一个C指针,但这确实会打乱您的其他Fortran调用。[我现在不多说了,因为我显然只是在猜测。]如果您将p2(:)作为伪参数接收到project()的包装器(这样包装器是C-可互操作的),那么我想没有必要用C重新编写project()。根据代码库的大小,我的建议可能不可行。但是,为什么不让函数返回一个
类型(c_ptr)
然后使用
调用c_f_指针(c_loc(old_c_ptr),fortran_ptr)
来确保正确的c语言样式转换。