Reputation: 335
Update: I changed psubstuff into a c_ptr as recommended and used a c_f_pointer to access bstuff. This was successful. However I still need a good t_stuff structure with the second member as a t_bstuff (for further code in the real world), so I created a copy of the t_stuff (the bind(c) version I called t_stuff_c), and am trying to copy the contents of the t_stuff_c structure into t_stuff. But I am getting a compilation error:
error #6285: There is no matching specific subroutine for this generic subroutine call. [C_F_POINTER]
I have a situation where a C++ main program is calling functions in a Fortran DLL. This comes from a very large project, so I have trimmed it down into a simple example which reproduces the problem I am having, which is:
The main C++ program creates a variable "stuff" of type "tstuff". "tstuff" contains just one element "substuff" which is of type "void*" (it has to be this way as in practice substuff is extremely large and complex on the F90 side and I can't and indeed don't need to reproduce it on the C++ side)
It then calls crfl() in the Fortran code which creates "substuff" on the Fortran side.
Then it calls the function stfl in the Fortran code to send the character "TEST" into the member substuff%clb%corf on the Fortran side. I step through the debugger in the Fortran code and all is good up to this point and "TEST" does indeed appear in the variable on the Fortran side.
Now it goes strange. The C++ code then calls the Fortran routine test2 passing the variable stuff. When I step into the F90 code, stuff%substuff%clb%corf contains garbage. The pointer to stuff is correct in the Fortran code as the text "ACF-C" is in the name variable. But substuff is garbage. It is important that the variable stuff%substuff is correct at this point as this variable is used further in the real code.
C Code:
#include <iostream>
#include <cstddef>
#include <vector>
using namespace std;
struct t_stuff {
char name[256];
void *substuff;
};
//Fortran subroutine definitions
extern "C" {
void test2(t_stuff *stuff);
}
extern "C"
{
void * crfl();
int stfl(void * cstuff, char * name);
}
int main()
{
int ierr;
t_stuff *stuff;
stuff = new t_stuff;
strcpy_s((*stuff).name, sizeof((*stuff).name), "ACF-C");
(*stuff).substuff = crfl();
ierr = stfl((*stuff).substuff, "TEST");
test2(stuff);
}
Fortran code:
module ftncode_mod use, intrinsic :: iso_c_binding implicit none
type, public :: t_clb
character(8) :: corf
end type
type, public :: t_bstuff
type (t_clb) :: clb
end type t_bstuff
type, public, bind(C) :: t_stuff_c
character(1) :: name(256)
type (c_ptr) :: psubstuff
end type t_stuff_c
type, public :: t_stuff
character :: name(256) = ' '
type (t_bstuff) :: psubstuff
end type t_stuff
contains
subroutine c2fstr(cptr,fstr)
type(c_ptr), value, intent(in ) :: cptr
character(*), intent(out) :: fstr
character(256), pointer :: lfstr
integer :: id
call c_f_pointer(cptr,lfstr)
id = index(lfstr,c_null_char)-1
if(id.le.0) id=len(lfstr)
fstr = lfstr(1:id)
end subroutine
function crfl() result(cp) bind(C)
!DEC$ ATTRIBUTES DLLEXPORT :: crfl
type(c_ptr ) :: cp
type(t_bstuff), pointer :: fp
allocate(fp)
cp = c_loc(fp)
end function
function stfl(cstuff,cne) result(ierr) bind(C)
!DEC$ Attributes dllexport :: stfl
type(c_ptr), value, intent(in) :: cstuff
type(c_ptr), value, intent(in) :: cne
integer :: ierr
type(t_bstuff) , pointer :: fstuff
character(24) :: cwk
ierr = 0
call c_f_pointer(cstuff,fstuff)
call c2fstr(cne,cwk)
fstuff%clb%corf = trim(cwk)
end function
subroutine test2(stuff) bind(C)
!DEC$ATTRIBUTES DLLEXPORT :: test2
use iso_c_binding
type(t_stuff_c), target, intent(in) :: stuff
type(t_stuff) :: fstuff
type(t_bstuff), pointer :: bstuff
integer :: i
call c_f_pointer(stuff%psubstuff,bstuff)
print *, "stuff%substuff%clb%corf: ", bstuff%clb%corf ! correct
! now need to populate the derived Fortran structure, fstuff
do i = 1, 256
if(stuff%name(i) == c_null_char) exit
fstuff%name(i:i) = stuff%name(i)
enddo
! and the pointer
call c_f_pointer(stuff,fstuff)
print *, "fstuff%substuff%clb%corf: ", fstuff%psubstuff%clb%corf
end subroutine test2
end module
Upvotes: 0
Views: 208