- 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