【问题标题】:Passing a dynamic 2D array from C++ to Fortran and back将动态二维数组从 C++ 传递到 Fortran 并返回
【发布时间】:2015-04-18 06:47:40
【问题描述】:

在 C++ 和 Fortran 之间传递一个固定的二维数组可以正常工作,但是对于我编写的将二维动态数组从 C++ 传递到 Fortran 的程序则不是这样。

C++端

extern "C" {void array2d_(double **, int *, int *); }
using namespace std;
int main()
{
double **array;
int nx=3;
int ny=2;
int i,j;
cout << "Passing dynamic array from C to Fortran\n";
array = (double **) malloc(nx * sizeof(double *));
if(array == NULL)
        {
        fprintf(stderr, "out of memory\n");
        exit;
        }
for(i = 0; i < nx; i++)
        {
        array[i] = (double *) malloc(ny * sizeof(double));
        if(array[i] == NULL)
            {
            fprintf(stderr, "out of memory\n");
            exit;
            }
        }
for(i = 0; i < nx; i++)
            {
            for(j = 0; j < ny; j++)
                {
                array[i][j]=i+j+i*(2+j)+4;  //random initialisation
                cout << "array[" << i << "][" << j << "]=" << array[i][j] << " ";
                }
            cout << endl;
            }

array2d_(array, &nx, &ny);

for(i = 0; i < nx; i++)
        free(array[i]);
    free(array);
return 0;
}

fortran 方面

subroutine array2d(arr,nx_C,ny_C) bind(C,name="array2d_")
use  iso_c_binding
implicit none
integer (C_INT), intent(IN) :: nx_C,ny_C          !array sizes from C
real (C_DOUBLE), intent(INOUT) :: arr(ny_C,nx_C)
integer :: k,l
print *, "This is in Fortran routine..."
do k = 1,ny_C
do l=1,nx_C
 print *, "arr(",k,",",l,") = ", arr(k,l)
end do
end do
end subroutine array2d

C++ 中的输出是

 array[0][0]=4 array[0][1]=5 
 array[1][0]=7 array[1][1]=9 
 array[2][0]=10 array[2][1]=13 

而在 Fortran 中,输出是

 arr(           1 ,           1 ) =    1.7994937190948764E-305
 arr(           1 ,           2 ) =    7.1027035167764720E-251
 arr(           1 ,           3 ) =    9.8813129168249309E-324
 arr(           2 ,           1 ) =    5.4809152658772852E-317
 arr(           2 ,           2 ) =    1.5475240269406953E-314
 arr(           2 ,           3 ) =    0.0000000000000000  

所以不知何故,这些值没有正确传递。

【问题讨论】:

  • 是的,很抱歉这是早期代码的一部分 - 结果当然不会改变,但我现在会改变它。
  • 顺便说一句,代码在这方面仍然不一致(intc_long),但这不会导致该错误。
  • 我希望我现在已经消除了不一致...

标签: c++ arrays fortran 2d fortran-iso-c-binding


【解决方案1】:

主要原因是您的 C 数组是一个锯齿状数组,它是一个指向分隔一维数组的指针数组,而在 Fortran 中,您将参数声明为一个连续的二维数组。您必须在两个部分中使用相同的,最好在 C 中也使用一个连续的数组。

只需malloc 一个大的nx*ny 缓冲区并将指针设置为行而不是分配它们。你可以在https://stackoverflow.com/a/5901671/721644看到一个例子

【讨论】:

  • 抱歉,您是说使用double*(大小为nx*ny)而不是double**?我不确定我是否遵循您的建议。你的意思是像double * array; array = (double*)malloc(nx*ny*sizeof(double))
  • 查看链接示例。您需要一个double**,但您必须进行不同的设置。数组必须是连续的。
  • 我用以下 double *data = (double *)malloc(nx*ny*sizeof(double)); array= (double **)malloc(nx*sizeof(double*)); for (int i=0; i&lt;nx; i++) array[i] = &amp;(data[ny*i]); 替换了所有初始化部分,但是我仍然在 Fortran 中得到相同的输出。
  • 是的,您必须确保您传递的是指向数据的指针,而不是指向指针的指针。您需要通过dataarray[0]&amp;(array[0][0]) 并且函数必须采用double *
  • 那么你是说在 Fortran 中我只能将数组作为一维从 C++ 传递以使其保持连续?
【解决方案2】:

我最近发现使用 C_F_POINTER 取得了一些成功,同时处理了一些需要在 Fotran 中保持数组形状(不能只是一维):

由于在从 C++ 传递动态分配的数组时,您正在传递指向值的指针数组的指针(对于 2D),因此您可以对每个 c_ptr 使用 C_F_POINTER() 方法来帮助您在 Fortran 端填充数组。

在您的 Fortran 子例程中,您将包含您的数组的变量设置为您的行的一维数组。这包含一个指针数组,每个指针指向一维指针数组,这些指针将用你的列填充你的行。在 Fortran 方面,您需要一个 Fortran 指针的一维数组和一个作为实际值的二维数组。

C++:

double** arrc = new double*[x]
for (i=0;i<x;i++)
    arrc[i] = new double*[y] 

some_fortran_call(arrc)

Fortran:

subroutine some_fortran_call(arrc) bind(c, name='some_fortran_call')
use iso_c_binding
type(c_ptr), intent(inout):: arrc(x)
real*8, pointer:: arrp(:)
real*8, dimension(:,:), allocatable:: arrf
allocate(arrf(x,y))

do i=1,x
    call C_F_POINTER(arrc(i), arrp, [y]) ----> Each pointer in arrc points to a 1D array with y values
    do j=1,y
        arrf(i,j) = arrp(j) ---------> Fills in ith row with y amount of values (will do this for all x rows)
    end do
end do

您仍然需要为 Fortran 数组分配新内存,但这至少节省了在 C++ 中分配新一维数组所需的内存。

【讨论】:

  • 什么是 Fortran x(和 y)?
  • 它们只是个傻瓜,其中 x 代表行数,y 代表数组的列数
猜你喜欢
  • 1970-01-01
  • 2015-05-30
  • 1970-01-01
  • 1970-01-01
  • 2016-04-06
  • 2012-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多