When I pass a pointer from Fortran to C++ the value of the first element is lost

I am calling a Fortran function from C++ which allocates a vector and then it returns a pointer from C++ to that vector. The problem is that when I print the values in C++ using this pointer, the value of the first element of the vector is lost. I am not sure if I am doing something wrong.

The following is my C++ code:

#include <iostream> 
#include <cstdio>

using namespace std;

extern"C" {
void fortfunc_(int *ii, void *ff);
}

main()
{

   int ii=5;
   double *ff;
   int i;

   // Calling my Fortran function:
   fortfunc_(&ii, &ff);

   printf("#C++ address: %p\n", ff);

   for (i=0; i<ii; i++)
        printf(" ff[%3d] = %f\n",i,ff[i]);

return 0;
}

My Fortran code:

subroutine fortfunc(ii,ffp)

use, intrinsic  :: iso_c_binding
integer(kind=4),  intent(in)  :: ii
type(C_PTR),      intent(out) :: ffp

real(kind=8),  dimension(:), allocatable, target :: ff
integer(kind=4) :: err, i

!Allocating memory for ff:
allocate(ff(ii),stat=err)
print *,'allocate returned: ',err

ffp = C_LOC(ff(1))

write(*,'(a,z20)') '#Fortran address:', C_LOC(ff(1))

do i=1,ii
    ff(i) = i
end do

print*,"Writing some vectors:"
print*,"ii = ",ii
print*,"ff= ",ff

return
end

If I run it I obtain the following output:

allocate returned:            0
#Fortran address:              3B5AE0
 Writing some vectors:
 ii =            5
 ff=    1.0000000000000000        2.0000000000000000        3.0000000000000000        4.0000000000000000        5.0000000000000000   
#C++ address: 003B5AE0
 ff[  0] = 0.000000
 ff[  1] = 2.000000
 ff[  2] = 3.000000
 ff[  3] = 4.000000
 ff[  4] = 5.000000

As you can see ff[0] = 0 and it must be 1.

Upvotes: 3

Views: 1143

Answers (1)

IanH
IanH

Reputation: 21431

If you are referencing the ISO_C_BINDING intrinsic module, then your Fortran compiler almost certainly supports the BIND(C) suffix for C interoperable Fortran procedures and interfaces. Put the suffix BIND(C, NAME='what_you_want_the_thing_called_in_C") on the subroutine statement, and avoid all the processor dependent silliness around the symbol name for the Fortran procedure. This also ensures that arguments are being passed in a C interoperable manner.

The variable ff in the Fortran subroutine is a local, unsaved allocatable variable. From Fortran 95 on, when the subroutine completes execution, it is automatically deallocated. The C address of the first element of that object then becomes invalid at that point - hence in the C code you are trying to dereference an invalid pointer (it points to memory that is no longer allocated).

You need to consider some way of managing the lifetime of the Fortran ff variable. One approach is to make it a Fortran pointer, and to provide a separate Fortran routine that indicates when that pointer can be deallocated.

Upvotes: 2

Related Questions