Felix
Felix

Reputation: 11

How to make Fortran pointers travel through C++

I'm trying to insert a C++ layer between two Fortran subroutines. I also need to pass as argument a derived type that I don't want to declare in C++, since I don't neet to access to its data, and it is in my original program a complex type, using in turn a lot of other types.

I made a simple Fortran program:

module my_module

  implicit none

  type :: my_type
    real :: x
  end type my_type

end module my_module

subroutine fortran_subroutine(b)

  use my_module
  implicit none

  type(my_type), pointer, intent(in) :: b

  print *, b%x

end subroutine fortran_subroutine

program test

  use my_module
  implicit none

  abstract interface
      subroutine sub (b)
        import :: my_type
        type(my_type), pointer, intent(in) :: b
      end subroutine sub
  end interface

  type(my_type), pointer :: a

  procedure (sub), pointer :: f_ptr => null ()
  procedure (sub) :: fortran_subroutine

  allocate(a)
  a%x = 1.0

  f_ptr => fortran_subroutine
  call c_plus_plus_layer(f_ptr,a)

end program

And here is the C++ intermediate layer:

extern "C" 
{
  void c_plus_plus_layer_(void (*pointer_to_fortran_function)(void **), void ** x);
}

// Intermediate layer of C++ designed to launch a Fortran subroutine
void c_plus_plus_layer_(void (*pointer_to_fortran_function)(void **), void ** x)
{
  pointer_to_fortran_function(x);
}

However, I get an error when reaching the print instruction when compiling with the Intel compilers (v13), as I lost the data stored within my derived type somewhere in the C++ layer.

The gcc and gfortran compilers do not return anything.

May I ask for your help ?

Upvotes: 1

Views: 157

Answers (1)

Fortran 2003 has a new way of interfacing with C. The module iso_c_binding declares a derived type type(c_ptr) that represents void* and the attribute value which lets you to pass the pointer by value. It also contains procedures c_loc() and c_f_pointer() for conversion of Fortran and C pointers.

For procedure pointers, similarly type(c_funptr), and procedures c_funloc() and c_f_procptr() are available.

Study a lot of questions and answers here in tag fortran-iso-c-binding

Also, by using the bind(C) attribute, you get similar effects es extern(C) in C++ and you do not have to worry about name mangling and the trailing_. The bind(C) attribute is important to achieve the true C behavior of the Fortran procedure, e.g., the value attribute.

Note that if you use bind(C) the compiler will often warn you or even raise an error that Fortran pointer attribute cannot be used in such a procedure, because C wouldn't understand it.

Upvotes: 5

Related Questions