- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I would like to pass a 2D dynamic array from C++ to a Fortran subroutine(dll) for some calculations and after that I would like to get the modified array back to my C++ program.
I have checked lots of documents but I didn't find a solution for my case. Similarly , IanH offers a solution from this forum (https://software.intel.com/en-us/forums/topic/288940) but it is not what I want to do. I don't want to construct the array inside Fortran subroutine, I would like to modify the existing one and get it back.
Also, from this link, Oracle documentation states that: "C pointers are compatible with Fortran 95 scalar pointers, but not array pointers." The C++ dynamic arrays are the 1D array of array pointers so my case seems inapplicable.
Would you offer any solution? What kind of approach should I follow?
Thanks in advance,
//C++ code
#include <iostream> extern "C" __declspec (dllimport) void FortCDLL(int*, int*,float **,const int*, const int*); int main () { const int row = 2; const int col = 3; int var1 = 5; int var2 = 6; // Allocate memory float **p2DArray = new float*[row]; for (int i = 0; i < row; ++i) p2DArray = new float[col]; // initialization for(int i = 0; i < row; i++) for(int j = 0; j < col; j++) p2DArray= (i + j) * i + j; //Call Fortran dll FortCDLL(&var1, &var2, array2D, &row, &col); return 0; }
//Fortran Subroutine
! FortCDLL.f90 ! ! FUNCTIONS/SUBROUTINES exported from FortCDLL.dll: ! FortCDLL - subroutine ! subroutine FortCDLL(VAR1, VAR2,C_ARR, ROW, COL) BIND(C, NAME="FortCDLL") USE, INTRINSIC :: ISO_C_BINDING IMPLICIT NONE !DEC$ ATTRIBUTES DLLEXPORT::FortCDLL ! Variables INTEGER(C_INT), INTENT(INOUT) :: VAR1, VAR2 REAL(C_FLOAT), POINTER :: arr(:,:) INTEGER(C_INT), INTENT(IN) :: ROW, COL TYPE(C_PTR), INTENT(IN) :: C_ARR !Dummy variables INTEGER DummyARR(ROW,COL) INTEGER VEC(2) INTEGER :: i, j ! Body of FortCDLL VEC = SHAPE(DummyARR) PRINT *, "Fortran DLL is called ... " CALL C_F_POINTER(C_ARR, arr, VEC) PRINT *, "### assignment ... ###" DO i = 1, ROW DO j = 1, COL arr (i, j) = (VAR1 + VAR2) * i + j PRINT *, "arr(",i,j,")= ", arr(i,j) END DO END DO VAR1 = VAR2 + 257; VAR2 = 34; PRINT *, "END of Fortran DLL ..." end subroutine FortCDLL
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi, Burak
If you want to pass a 2D dynamic array from C++ to a Fortran, you can declare the it to be an 1D dynamic array in c++. Actually Array[2][3] is the same with Array[6] in memory, c++ store the array continously row by row. Be careful in:
- c++/c stores array is row-major, while Fortran stores array in column-major order. So you need to do some kind of conversion.
- Use correct data type mapping, e.g. c++ double – fortran real(8), c++ float – fortran real(4).
I modified your example a little bit. You can see it works now.
c++:
extern "C"
{
extern void __stdcall test(int*, int*,float *,const int*, const int*);
}
int _tmain(int argc, _TCHAR* argv[])
{
const int row = 2;
const int col = 3;
int var1 = 5;
int var2 = 6;
// Allocate memory
float *p2DArray = new float [row*col];
// initialization
for(int i = 0; i < row; i++)
for(int j = 0; j < col; j++)
p2DArray[i*col+j] = (i + j) * i + j;
//Call Fortran dll
test(&var1, &var2, p2DArray, &row, &col);
return 0;
}
Fortran:
SUBROUTINE test ( VAR1, VAR2, ARR, ROW, COL )
CDEC$ ATTRIBUTES DLLEXPORT, STDCALL :: test
CDEC$ ATTRIBUTES REFERENCE ::VAR1, VAR2, ARR, ROW, COL
IMPLICIT NONE
INTEGER, INTENT(INOUT) :: VAR1, VAR2
INTEGER, INTENT(IN) :: ROW, COL
REAL(4), INTENT(INOUT) :: ARR(ROW, COL)
INTEGER :: i, j
DO i = 1, ROW
DO j = 1, COL
ARR (i, j) = (VAR1 + VAR2) * i + j
END DO
END DO
VAR1 = VAR2 + 257
VAR2 = 34
end subroutine test
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
One option is on the C++ side is to allocate the 2D array of floats as 1D and assigned to the first pointer of pointers, then fill in the remainder pointers in the array of pointers with the proper offset. And on the Fortran side you can now create the 2D array descriptor. One call to new on C++ side, no copy on Fortran side.
The other option where C++ side uses multiple new's, and is what you are attempting to do is to define a type that is a 1D pointer to an array of floats, then define an array of these pointers
outline:
type p1D real, pointer :: a(:) end type p1D type(p1D) :: arrayOfp1d(:) ... allocate(arrayOfp1d(nRows)) // then initialize the pointers to the corrisponding locations in the C++ array of pointers ... then DO i = 1, ROW DO j = 1, COL arrayOfp1d(i)%a(j) = (VAR1 + VAR2) * i + j PRINT *, "arr(",i,j,")= ", arrayOfp1d(i)%a(j) END DO END DO
Jim Dempsey
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page