Community
cancel
Showing results for 
Search instead for 
Did you mean: 
GeoffH
Novice
175 Views

Fortran interface to call a C function that returns a pointer to an array

Jump to solution

Back again after being away for quite a while...

After much searching, I found what I believe to be the closest answer to my problem is on stackoverflow (SO) at https://stackoverflow.com/questions/3852790/fortran-interface-to-call-a-c-function-that-return-a-poi..., (posted nearly 10 years ago!)

I quote this because using that example keeps the code simple and still illustrates my problem.

I want to return an array that has been created/memory allocated in C++ and be able to analyse the answer in Fortran, because that is where the bulk of the code for this application lies. My application goes off into C++ to produce the integer array answer and returns it to the Fortran program via the C interface. The original SO example used a single double precision variable as the return. I’ve changed it to integer because that is what I will be dealing with in my application. The example code (as changed) works.

I have highlighted with comments the changes that I have tried to make to return an array pointer, but I’ve run out of ideas. (I could say, “Oh for the bad old days when I could just equivalence an integer to an iarray(1) and go beyond the size of the array”, but I won’t. It’s good to have coding protections, but sometimes it gets frustrating.)

I am using Visual Studio 2017 and Intel Fortran parallel_studio_xe_2019_update5_composer.

My modified example of the original SO code:

[code here

! ps_test_pointers.f90

program foo

  use, intrinsic :: iso_c_binding, only : c_ptr,        &

                                          c_f_pointer,  &

                                          c_int

  implicit none

  type(c_ptr) :: c_p!(:) ! <-------

  integer(c_int), pointer :: f_p!(:) ! <-------

  interface

    function foofunc() bind(c)

      import :: c_ptr

      implicit none 

      type(c_ptr) :: foofunc!(:) ! <-------

    end function foofunc

  end interface

  c_p = foofunc()

  call c_f_pointer(c_p, f_p)

  print *, f_p

end program foo

##########################################################

// ps_test_pointersC.cpp : 'Subroutine' only.

extern "C" {

    int bar[3] = { 2, 3, 4 };

       int *foofunc() {

        return bar;

    }

}

]

As I said above, the code works, in the sense that it prints out the first element of the array (‘2’).

If I add the ‘(:)’ to the definition of f_p, the code compiles without error, but when I run it, the program fails with the run-time error: “forrtl: severe (408): fort: (7): Attempt to use pointer F_P when it is not associated with a target” at the line “call c_f_pointer(c_p, f_p)”.

I have tried declaring c_p as an array (“c_p(:)”), but I get the same error in the same place.

I have also tried calling c_p as an argument to a subroutine – still only using integers

[code here

! ps_test_pointers.f90

program foo

  use, intrinsic :: iso_c_binding, only : c_ptr,        &

                                          c_f_pointer,  &

                                          c_int

  implicit none

  type(c_ptr) :: c_p!(:) ! <-------

  integer(c_int), pointer :: f_p!(:) ! <-------

  interface

    subroutine foofunc(c_p) bind(c)

      import :: c_ptr

      implicit none 

      type(c_ptr) :: c_p!(:) ! <-------

    end subroutine foofunc

  end interface

  call foofunc(c_p)

  call c_f_pointer(c_p, f_p)

  print *, f_p

end program foo

##########################################################

// ps_test_pointersC.cpp : 'Subroutine' only.

extern "C" {

    int bar[3] = { 2, 3, 4 };

       void foofunc(int *rtn) {

        rtn = bar;

    }

}

]

but the created pointer in the C function never gets assigned to c_p on return (hence f_p is never defined).

Reading around the problem, I hope I’m not at the bleeding edge of compiler implementation and have exposed a problem between restrictions tightening but not coping with all the use cases!

Is there a solution to this? Any?

Contributions will be gratefully received!

0 Kudos

Accepted Solutions
Arjen_Markus
Valued Contributor III
166 Views

I think you are working a trifle too hard here:

type(c_ptr) :: c_p(:) would be an array of C pointers, not a C pointer to a C array.

type(cptr) :: c_p is the one you need, because C returns an array and whatever is behind that address is of no interest to the declaration on the Fortran side, because C does not pass on this information.

To turn c_p into an array on the Fortran side use:

call c_f_pointer( c_p, f_p, [3] )  ! [3] is the shape of the resulting Fortran array - fill in whatever is needed

I may be overlooking something - I have not tried it, but this is the principle :).

View solution in original post

3 Replies
Arjen_Markus
Valued Contributor III
167 Views

I think you are working a trifle too hard here:

type(c_ptr) :: c_p(:) would be an array of C pointers, not a C pointer to a C array.

type(cptr) :: c_p is the one you need, because C returns an array and whatever is behind that address is of no interest to the declaration on the Fortran side, because C does not pass on this information.

To turn c_p into an array on the Fortran side use:

call c_f_pointer( c_p, f_p, [3] )  ! [3] is the shape of the resulting Fortran array - fill in whatever is needed

I may be overlooking something - I have not tried it, but this is the principle :).

View solution in original post

GeoffH
Novice
148 Views

Thank you Arjen_Markus. That's part of the solution. I hinted that this example is a very simplified form of my problem that illustrates the issue. That said, I do have the size of the array in the returned pointer array and I can extract that and return it in the foofunc (or more accurately for a Fortran user, foosub).

I still have some more work to do to get all the info back into the Fortran program, but you have broken my deadlock. Thanks.

GeoffH
Novice
104 Views

Yep. All working now.