简体   繁体   English

将动态二维数组从 C++ 传递到 Fortran 并返回

[英]Passing a dynamic 2D array from C++ to Fortran and back

Passing a fixed 2D array between C++ and Fortran works fine, however not so with the program I have written to pass a 2D dynamic array from C++ to Fortran.在 C++ 和 Fortran 之间传递一个固定的二维数组可以正常工作,但是对于我编写的将二维动态数组从 C++ 传递到 Fortran 的程序则不是这样。

C++ side 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;
}

The fortran side 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

The output in C++ is 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 

While in Fortran the output is在 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  

So somehow the values are not passed correctly.所以不知何故,这些值没有正确传递。

The main reason is that your C array is a jagged array, it is an array of pointers to separate 1D arrays while in Fortran you declare ther argument to be a contiguous 2D array. 主要原因是您的C数组是一个锯齿状的数组,它是指向1D数组的指针的数组,而在Fortran中,您将r参数声明为连续的2D数组。 You must use the same in both parts, preferably use a contiguous array in C too. 您必须在两个部分中都使用相同的数组,最好在C中也使用连续数组。

Just malloc one big nx*ny buffer and set the pointers to the rows instead of alloacating them. 只需malloc一个大的nx*ny缓冲区并将指针设置为行,而不是分配它们。 You can see an example in https://stackoverflow.com/a/5901671/721644 您可以在https://stackoverflow.com/a/5901671/721644中看到一个示例

I recently found some success using C_F_POINTER while working on something that needed to maintain the array shape in Fotran (couldn't just be 1D):我最近发现使用 C_F_POINTER 取得了一些成功,同时处理了一些需要在 Fotran 中保持数组形状的东西(不能只是一维的):

Since you are passing pointers to arrays of pointers to values (for 2D) when passing dynamically allocated arrays from C++, you can use the C_F_POINTER() method for each c_ptr to help you fill in arrays on the Fortran side.由于您在从 C++ 传递动态分配的数组时传递指向值的指针数组的指针(对于 2D),因此您可以对每个 c_ptr 使用 C_F_POINTER() 方法来帮助您在 Fortran 端填充数组。

In your Fortran subroutine, you set the variable containing your array as a 1D array of your rows.在 Fortran 子例程中,将包含数组的变量设置为行的一维数组。 This contains an array of pointers which each point to 1D arrays of pointers that will fill in your rows with your columns.这包含一个指针数组,每个指针都指向一维指针数组,这些指针将用你的列填充你的行。 On the Fortran side, you'll need a 1D array of Fortran pointers and a 2D array that will be your actual values.在 Fortran 方面,您需要一个 Fortran 指针的一维数组和一个作为实际值的二维数组。

C++: C++:

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

some_fortran_call(arrc)

Fortran: 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

You still need to allocate new memory for the Fortran array but this at least saves the memory needed to allocate a new 1D array in C++.您仍然需要为 Fortran 数组分配新内存,但这至少节省了在 C++ 中分配新一维数组所需的内存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM