Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28593 Discussions

Problem passing array from C++ to Fortran DLL

Dominic_C_1
Beginner
1,007 Views

Hi,

Apologies for posting my second topic today, but I have searched high and low for a solution to this particular problem and cannot break through it.

I am trying to call a Fortran subroutine (in a DLL) from C++ code, and the subroutine has some allocatable arrays as arguments.

When I step into the subroutine code, the array always shows up as "Undefined pointer/array", so my data is not getting passed in, even though it looks correct on C++ side

Other non dimensional arguments are working fine.

Here is my Fortran code:

subroutine Tick(initial_time,seconds_to_simulate,                                                       & 
                  agents_in_time, agents_in_door,)
  !DEC$ ATTRIBUTES DLLEXPORT::Tick
    
    real(kind=DP), intent(in)                               :: initial_time        !works fine
    real(kind=DP), intent(in)                               :: seconds_to_simulate    !works fine
    integer, dimension(:), allocatable, intent(in)          :: agents_in_door  !NOT WORKING
    real(kind=DP), dimension(:), allocatable, intent(in)    :: agents_in_time  !NOT WORKING
    
    !initial_time and seconds_to_simulate are passed in fine
    
    !agents_in_time and agents_in_door just show up as "Undefined pointer/array"

And here is my C++ code (example)

double starttime = 0;
double timeStep = 10;
double* agentsInTime;
int agents_in_door;
agents_in_time = new double[numNewAgents];
agents_in_door = new int[numNewAgents];
for(int i = 0; i<numNewAgents; ++i)
{
    agents_in_time = currentTime;
    agents_in_door = currentdoor;
}

//Call Tick...passing in the addresses of the 4 arguments, but agents_in_time and agents_in_door are not passed through
Tick(&startTime, &timeStep, &agents_in_time, &agents_in_door)

Anyone have any ideas?

Thanks

0 Kudos
5 Replies
mecej4
Honored Contributor III
1,007 Views

Your program has several errors, the nature of which indicate that you should first work with some pre-tested examples of using C and Fortran together.

Do not try to use allocatable and deferred size array arguments. Since, in your C caller, the arrays are allocated before the call to the Fortran subroutine, there is no need to mark the arrays as allocatable. 

In C, if a variable is an array or a pointer, do not apply the '&' operator to the variable name when passing it to Fortran. In other words, pass the pointer, not the address of the pointer.

The C and Fortran compilers have certain conventions regarding external names. Learn and observe those conventions.

Here is your code, modified to run and give reasonable results, in 32 or 64 bit Windows. If you wish to put the Fortran code in a DLL, you can do so later. It is better to get the bugs removed with static linking before attempting to use dynamic linking.

The Fortran subroutine:

subroutine Tick(initial_time,seconds_to_simulate,                                                       & 
                  agents_in_time, agents_in_door)
    integer, parameter :: DP = kind(0d0)
    real(kind=DP), intent(in)                               :: initial_time        !works fine
    real(kind=DP), intent(in)                               :: seconds_to_simulate    !works fine
    integer, dimension(*)          :: agents_in_door
    real(kind=DP), dimension(*)    :: agents_in_time
    integer :: i
    do i=1,5
     agents_in_door(i)=2*agents_in_door(i)-1
     agents_in_time(i)=sin(3.1416*0.2*i)
   end do
   return
   end subroutine

The C caller:

#include <stdio.h>
#define numNewAgents 5

double starttime = 0;
double timeStep = 10;
double agents_in_time[numNewAgents];
int agents_in_door[numNewAgents];
main(){
	double startTime,timeStep;
for(int i = 0; i<numNewAgents; ++i){
    agents_in_time =2.5;
    agents_in_door = 15-i;
    }

TICK(&startTime, &timeStep, agents_in_time, agents_in_door);

for(int i=0; i<numNewAgents; i++)
   printf("%2d %3d %6.3f\n",i,agents_in_door,agents_in_time);
}

To build, use the commands

ifort /c fsub.f90
icl cmain.c fsub.obj

 

0 Kudos
Dominic_C_1
Beginner
1,007 Views

Wow, thanks for this response.

I should have mentioned that the Fortran code isn't mine, I have been given the task of integrating it into our C++ code so I am not familiar with it (no excuse though).

And also, I made a mistake when I truncated the code, so of course there shouldn't be an & symbol before the array that I pass into the Fortran subroutine, that was a mistake.

It looks like the issue I was having was down to changing this:

real(kind=DP), dimension(:), allocatable, intent(in)    :: agents_in_time  !NOT WORKING

to this:

real(kind=DP), dimension(*)    :: agents_in_time

After making these changes, the data is passing through correctly. 

Is it possible to know what size the array is that is passed through without sending a size value along with the array? The array will not always be the same size.

Thnaks again for the help.

0 Kudos
mecej4
Honored Contributor III
1,007 Views

Dominic C. wrote:
Is it possible to know what size the array is that is passed through without sending a size value along with the array? The array will not always be the same size.

In general, and in a way that will work with any combination of Fortran and C compilers? -- that is not possible, just as it is not possible in pure C (note: I exclude C++). If you look at widely used libraries such as Intel MKL, IMSL, NAG, etc., you will find that, for each array argument, the actual array size (which may be less or equal to the declared/allocated size) is passed to a library subroutine as an extra integer argument.

If you are implementing this kind of C <--> Fortran linkage in a large project, it would be worth your while to read about the Fortran 2003 C-interoperability features.

0 Kudos
Steven_L_Intel1
Employee
1,007 Views

Fortran 2015 adds a concept called "C Descriptors" which allows C code to pass additional information to Fortran, including array bounds and even whether it is allocatable or not. We will implement this in the 16.0 compiler (Beta is running now.) It would mean some additional code on the C side. Otherwise, you must pass the array extent as a separate argument and use that in your Fortran declaration.

0 Kudos
Dominic_C_1
Beginner
1,007 Views

To both of you, thanks so much for your help, I really appreciate it.

0 Kudos
Reply