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

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

GeoffH
Novice
302 Views

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
1 Solution
Arjen_Markus
Valued Contributor III
293 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
294 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 :).

GeoffH
Novice
275 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
231 Views
Reply