- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Is there a way to access a C++ object from a Fortran subroutine? My subroutine is like this:
subroutine fsub(...)
! If first time calling, call to a cpp function and do initialization (i.e., create the c++ object) .
! Call to a cpp function which will access to the c++ object and do calculations.
end
The subroutine "fsub" will be called by the Fortran "main" program many times. I guess the problem is how to keep the c++ object alive each time after the subroutine "fsub" returns and how to access the c++ object in the next time.
I have been stuck and frustrated on this problem for weeks. Appreciate any assistance.
Thanks,
Jason
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jason L. wrote:
Is there a way to access a C++ object from a Fortran subroutine? My subroutine is like this:
subroutine fsub(...)
! If first time calling, call to a cpp function and do initialization (i.e., create the c++ object) .
! Call to a cpp function which will access to the c++ object and do calculations.
end
The subroutine "fsub" will be called by the Fortran "main" program many times. I guess the problem is how to keep the c++ object alive each time after the subroutine "fsub" returns and how to access the c++ object in the next time.
I have been stuck and frustrated on this problem for weeks. Appreciate any assistance.
Thanks,
Jason
@Jason,
Sorry to read you "have been stuck and frustrated on this problem for weeks".
Please note Fortran does NOT provide direct interoperability with C++ classes and Fortran code can have no direct understanding of object instances created in C++. Rather Fortran provides interoperability with the C companion processor which you will know is similar to what C++ provides with extern "C" entities. Other more knowledgeable Fortran and C++ experts may be able to guide you toward better solutions toward your needs, but if I understood your post correctly, then what I suggest you try is a wrapper layer using appropriate extern "C" functions for the operations involving your C++ classes and utilize, as is commonly done in C <-> C++ invocations, an opaque pointer to the C++ object instance in these functions. Do pay close attention to the lifecycle of the C++ instance, holding a reference to the opaque pointer from your Fortran code and to instantiate the class as needed and to delete it when done. Shown below is an example illustrating this scheme using a simple-minded C++ class for an integer stack. Note you should be able to make do without any actual C code.
Hope this helps, good luck with your work.
#include <iostream>
using namespace std;
class IntStack
{
public:
   IntStack(int num) {  top = 0; maxelem = num; s = new int[maxelem]; }
   ~IntStack() { if (s != nullptr) delete[] s; }
   void  push(int t)
   {
      if (top == maxelem) return;
      s[top++] = t;
   }
   int pop()
   {
      if (top == 0) return -1;
      return s[--top];
   }
   void display()
   {
     cout << "IntStack::Display\n";
     if (top == 0) { cout << "(empty)\n";  return; }
     for (int t=0 ; t < top ; t++) cout << s << " ";
     cout << "\n";
   }
   int   empty()  {  return top == 0;  }
private:
   int *s;
   int top;
   int maxelem;
};
typedef void * OpaqueObject;
// Function prototypes
extern "C" {
   OpaqueObject GetObject(int);
   void ExerciseObject1(OpaqueObject, int);
   void ExerciseObject2(OpaqueObject);
   void DeleteObject(OpaqueObject);
}
OpaqueObject GetObject(int s_size) {
   IntStack *s = new IntStack(s_size);
   return (OpaqueObject)s;
}
void ExerciseObject1(OpaqueObject foo, int i) {
   IntStack *s = (IntStack *)foo;
   s->push(i);
   return;
}
void DeleteObject(OpaqueObject foo) {
   IntStack *s = (IntStack *)foo;
   delete(s);
   return;
}
void ExerciseObject2(OpaqueObject foo) {
   IntStack *s = (IntStack *)foo;
   s->display();
   return;
}
 
module m
   use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_null_ptr, c_associated
   implicit none
   private
   interface
      function GetObject( s_size ) result( optr )bind(C, name="GetObject")
         import :: c_int, c_ptr
         implicit none
         ! Argument list
         integer(c_int), intent(in), value :: s_size
         ! Function result
         type(c_ptr) :: optr
      end function GetObject
      subroutine ExerciseObject1( optr, ival ) bind(C, name="ExerciseObject1")
         import :: c_int, c_ptr
         implicit none
         ! Argument list
         type(c_ptr), intent(in), value :: optr
         integer(c_int), intent(in), value :: ival
      end subroutine ExerciseObject1
      subroutine ExerciseObject2( optr ) bind(C, name="ExerciseObject2")
         import :: c_ptr
         implicit none
         ! Argument list
         type(c_ptr), intent(in), value :: optr
      end subroutine ExerciseObject2
      subroutine DeleteObject( optr ) bind(C, name="DeleteObject")
         import :: c_ptr
         implicit none
         ! Argument list
         type(c_ptr), intent(in), value :: optr
      end subroutine DeleteObject
   end interface
   ! Hold Object
   type(c_ptr), save :: obj = c_null_ptr
   public :: Create
   public :: Employ
   public :: Destroy
contains
   subroutine Create( prob_size )
      ! Argument list
      integer(c_int), intent(in) :: prob_size
      if ( c_associated(obj) ) then
         call DeleteObject( obj )
      end if
      obj = GetObject( s_size=prob_size )
      return
   end subroutine Create
   subroutine Employ( dat )
      ! Argument list
      integer(c_int), intent(in) :: dat
      if ( c_associated(obj) ) then
         call ExerciseObject1( obj, ival=dat )
         call ExerciseObject2( obj )
      end if
      return
   end subroutine Employ
   subroutine Destroy()
      ! Argument list
      if ( c_associated(obj) ) then
         call DeleteObject( obj )
         obj = c_null_ptr
      end if
      return
   end subroutine Destroy
end module m
program p use, intrinsic :: iso_fortran_env, only : compiler_version use m, only : Create, Employ, Destroy print *, "Compiler Version: ", compiler_version() ! Create C++ object call Create( 10 ) ! Use the object a few times call Employ( 1 ) call Employ( 2 ) call Employ( 3 ) ! Destroy the object before program termination call Destroy() stop end program p
Upon execution,
Compiler Version: Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel( R) 64, Version 18.0.0.065 Beta Build 20170320 IntStack::Display 1 IntStack::Display 1 2 IntStack::Display 1 2 3 Press any key to continue . . .
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for this example....
Please note it does not give the same thing with gcc (would you know how to modify the code ?)
Pierre
 Compiler Version: GCC version 6.3.0 20170516
IntStack::Display
0x5611f730cb90
IntStack::Display
0x5611f730cb90 0x5611f730cb90
IntStack::Display
0x5611f730cb90 0x5611f730cb90 0x5611f730cb90
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have not tried the code, but this line:
for (int t=0 ; t < top ; t++) cout << s << " ";should probably be:
for (int t=0 ; t < top ; t++) cout << s[t] << " ";Otherwise the address of s is printed - s is an array after all.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you very much! It seems to be exactly what I need.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks to @FortranFan for kindly sharing this code. Can you kindly show usage of namespace for classes?
best,
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello @FortranFan,
I have tested your code, and it works. So thank you. I'm interested in the use of the s array in fortran. I tried to modify it to get the s pointer of C++ and use it in fortran but I failed. I don't know how to declare s in fortran to obtain a subroutine GetS( s ) bind(C, name="GetS") who would permit me to get it.
I wish you could advise me on this problem.
Thanks.
Romain
 
					
				
				
			
		
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page