Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
29280 Discussions

Passing dynamic allocated 2D arrays to Fortran subroutine in C++

danielwood
Beginner
716 Views

Hello All,

I tried to pass a dynamic allocated 2D array to a Fortran DLL subroutine in C++.

Please check the following codes. Output on the screen reads like:

4.240000 3.240000 5.240000
4.240000 3.240000 5.240000
4.240000 3.240000 5.240000
4.240000 3.240000 5.240000
4.240000 3.240000 5.240000
4.240000 3.240000 5.240000
4.240000 3.240000 5.240000
4.240000 3.240000 5.240000
6.115449276184175E-307 6.117241938228800E-307 0.000000000000000E+000
0.000000000000000E+000 4.24000000000000 -2.530171125652461E-098
3.897964094641386E-308 2.121995802822848E-314

6.116046830199050E-307 -2.530171125652461E-098 3.897987436627466E-308
2.121995802822848E-314 3.24000000000000 -2.656983832617227E+303
6.115639407007020E-307 -7.845907716021313E+298

6.116644384213925E-307 -2.656983832617227E+303 6.115340629999576E-307
-7.845907716021312E+298 5.24000000000000 0.000000000000000E+000
0.000000000000000E+000 4.24000000000000



It looks like C++ did not pass correct address/values to Fortran.

Please give me some hints and suggestions.

Thank you.

//------------------------------------------------------------------------------------------------------------------------------
/* Main program written in C++ that calls a Fortran routine */
//------------------------------------------------------------------------------------------------------------------------------
#include
#include
#include

#ifdef __cplusplus
extern "C"
#endif

#ifdef USEDLL
__declspec(dllimport)
#endif

void TESTDLL(double **); // Fortran DLL Subroutine

void updateinput(double **);

void main ()
{

//double log_DATA_TEMP[8][3];
double **log_DATA_TEMP;

int i;

log_DATA_TEMP=new double* [8];
for (int i=0; i<8; ++i) {
log_DATA_TEMP=new double [3];
for (int j=0; j<3; ++j) {
log_DATA_TEMP=0.0;
}
}

updateinput(log_DATA_TEMP);

for (i=0;i<8;i++)
{
printf("%lf %lf %lf\\n",log_DATA_TEMP[0],log_DATA_TEMP[1],log_DATA_TEMP[2]);
}

TESTDLL(log_DATA_TEMP);

for(i = 0; i < 8; i++)
delete(log_DATA_TEMP);
delete(log_DATA_TEMP);

}

void updateinput(double **DATA)
{
int i;
for (i=0;i<8;i++)
{
DATA[0]=4.24;
DATA[1]=3.24;
DATA[2]=5.24;
}
}


!---------------------------------------------------------------------------------------------------------------
! TESTDLL.f90
!---------------------------------------------------------------------------------------------------------------
! FUNCTIONS/SUBROUTINES exported from TESTDLL.dll:
subroutine TESTDLL(inputdata)
! Expose subroutine TESTDLL to users of this DLL
!
!DEC$ ATTRIBUTES DLLEXPORT::TESTDLL

Real(8)::inputdata(3,8);
Integer::i
!
Do i=1,3
Write(*,*) inputdata(i,:)
Write(*,*)
Enddo

end subroutine TESTDLL


0 Kudos
2 Replies
IanH
Honored Contributor III
716 Views
You are passing an pointer-to-pointer-to-double (an array of arrays, two levels of indirection) to a fortran function that just expects a pointer-to-double (just one big array, one level of indirection). double[] and double ** aren't the same thing, despite what the syntax might suggest.

Best option if your array is rectangular is to just create one chunk of memory on the C++ side:

[cpp]extern "C" void TESTDLL(double *);
...
double* log_DATA_TEMP = new double [8 * 3];    // in C++ consider using std::vector
...
   log_DATA_TEMP[i*3+j] = some_value;
...
TESTDLL(log_DATA_TEMP);

delete [] log_DATA_TEMP; // note array delete
[/cpp]

Reference the memory on the fortran side as input_data(j,i).

Alternatively, make the fortran handle two levels of indirection:

[fortran]subroutine TESTDLL(input_data) BIND(C, NAME='TESTDLL')  
  USE ISO_C_BINDING, ONLY: C_DOUBLE, C_PTR, C_F_POINTER
  TYPE(C_PTR), INTENT(IN) :: input_data(*)
  REAL(C_DOUBLE), POINTER :: array(:)
...
  DO i = 1, 8
    CALL C_F_POINTER(input_data(i), array, [3])
    DO j = 1, 3
      ! do something with array(j)...
...[/fortran]
This potentially allows you to process "arrays" with varying row lengths.

Apologies if my head C++ compiler/Fortran processor has failed me.
0 Kudos
danielwood
Beginner
716 Views
Hello IanH,

Thank you a lot.

I also did some extra homework here. Thoese two solutions suggested by you should be good approaches.

Thanks again.
0 Kudos
Reply