I have a Fortran DLL which is called from a C program, and one of my procedures needs periodically to call a callback function which is supplied by the C program. I currently have it working well in its 'simple' form, but I'd like to be able to store my callback pointer inside a derived type, so that it can be passed around within my Fortran code more easily. So far, nothing I've tried seems to work.
To begin with, here is what I have at the moment, and this does work:
Starting in the C (OK, actually C++) program, the header prototype for the callback is:
typedef void (*fcb)(void *)
and the prototype for the Fortran call is:
extern "C" __declspec(dllexport) int fortran_function(int n,
uchar *image_buffer,
fcb callback,
void *object);
The actual callback function is:
void callback(void* pObject)
{
// Cast the void pointer back to the appropriate class type:
MyClass *pMyObject = static_cast<MyClass *>(pObject);
pMyObject -> updateImageInGUI();
}
and the call to the Fortran code from C++ is:
int error = fortran_function(m_image.size(), m_image.data, callback, this);
where m_image is an array of image data which is a member attribute of the current object. What happens is that the C++ passes the raw image data to the Fortran DLL and asks the Fortran to process it, and since this takes a long time the Fortran periodically updates the image buffer and calls the callback to refresh the GUI. Anyway, moving on to the Fortran side, we define an interface for the C callback:
abstract interface
subroutine c_callback(c_object) bind(c)
use, intrinsic :: iso_c_binding
type(c_ptr), intent(in) :: c_object
end subroutine c_callback
end interface
and define our main Fortran routine thus:
integer(c_int) fortran_function(n, image, callback, c_object) &
bind(c, name='fortran_function')
integer(c_int), value :: n
integer(4), intent(inout), dimension(n) :: image
procedure(c_callback) :: callback
type(c_ptr), intent(in) :: c_object
Somewhere in the main routine we call our subroutine, foo:
call foo(data, callback, c_object)
...where foo is defined as:
subroutine foo(data, callback, c_object)
type(my_type), intent(inout) :: data
procedure(c_callback) :: callback
type(c_ptr), intent(in) :: c_object
...
call callback(c_object)
...
end function foo
As I said, all of this works well and has done so for a long time.
Now for the things I've tried but which don't work:
The naive approach, just copying the arguments into the fields of a structure
I'd expect this to work, since all all I'm doing is to copy the original elements into a structure with no modification. Nothing changes on the C side, nor in the definition of the main Fortran function nor the abstract interface to c_callback. All I do is to create a new Fortran derived type:
type :: callback_data
procedure(c_callback), pointer, nopass :: callback => null()
type(c_ptr) :: c_object
end type callback_data
and then in my main function I populate this with the values received from the C application:
data%callback_data%callback => callback
data%callback_data%c_object = c_object
call foo(data)
The subroutine foo has been slightly modified so that it now looks for the callback and C object within the structure:
subroutine foo(data)
type(my_augmented_type), intent(inout) :: data
...
call data%callback_data%callback(data%callback_data%c_object)
...
end function foo
This fails at the call with an "access violation reading location 0xffffffffffffffff".
The sophisticated approach using more of the iso_c_binding features
Again nothing changes on the C side but I modify the Fortran side of the main function to receive the callback as a c_funptr:
integer(c_int) fortran_function(n, image, callback, c_object) &
bind(c, name='fortran_function')
integer(c_int), value :: n
integer(4), intent(inout), dimension(n) :: image
type(c_funptr), intent(in) :: callback
type(c_ptr), intent(in) :: c_object
I define the abstract interface to subroutine c_callback just as before, though I've experimented both with leaving the bind(c) part of it in, and omitting it. The code within the main function that calls the subroutine foo is now:
call c_f_procpointer(callback, data%callback_data%callback)
data%callback_data%c_object = c_object
call foo(data)
...with the subroutine foo itself still defined as in the previous example.
Unfortunately this fails in exactly the same way as the previous example.
I assume that there is a correct syntax to achieve what I'm trying to achieve here, and I'd be very grateful for any advice.
A dummy argument in a Fortran procedure with the BIND(C) attribute that doesn't have the VALUE argument is equivalent on the C side to a pointer parameter (this is broadly consistent with the usual Fortran convention of things being passed by reference). So if on the Fortran side you have INTEGER(C_INT) :: a (no value attribute), that's equivalent on the C side to int *a.
Perhaps that's obvious, but it has a surprising consequence - if you have TYPE(C_PTR) :: p, that's equivalent to void **p - a C_PTR is a pointer, so a C_PTR passed without value is a pointer to a pointer. Given this, your interface for the callback is out (you need to add VALUE).
The interoperable analogue in a type sense to a C pointer to a function (which is what a function name sans parentheses is in C) in Fortran is a TYPE(C_FUNPTR). The same considerations with respect to the absence of the VALUE attribute and C_PTR apply - an argument declared TYPE(C_FUNPTR) :: f is a pointer to a pointer to a function. Given this and your C side call of the Fortran, the argument corresponding to the function pointer should have the VALUE attribute.
The fact that a Fortran procedure pointer happens to work is just a (not terribly surprising) coincidence of the underlying implementation of C function pointers and Fortran procedure pointers, and the way that Fortran procedure pointers are passed.
All up, your Fortran procedure probably needs to have an interface that looks like:
integer(c_int) fortran_function(n, image, callback, c_object) &
bind(c, name='fortran_function')
integer(c_int), value :: n
integer(c_signed_char), intent(inout), dimension(n) :: image
type(c_funptr), intent(in), value :: callback
type(c_ptr), intent(in), value :: c_object
(your declaration of the image array in your original code seems astray - perhaps the above is appropriate, perhaps not)
and your declaration of the interface of the C callback needs to have an interface of:
abstract interface
subroutine c_callback(c_object) bind(c)
use, intrinsic :: iso_c_binding
implicit none
type(c_ptr), intent(in), value :: c_object
end subroutine c_callback
end interface
(As discussed on the Intel fora over the last few months (where have you been?), current ifort may have a problem with it's handling of C_PTR and VALUE.)
Related
I have a Fortran function which compiled with previous versions of Intel Fortran Compiler (ifort), but is rejected by more recent versions (2021.6.0), and I hope to fix it. This function accepts a class(*), and passes its address and length to a C function:
!> Send an arbitrary scalar object.
function SendObject(my,obj) result(ok)
use, intrinsic :: iso_c_binding
implicit none
class(Socket) :: my
class(*), target, intent(in) :: obj
type(c_ptr) :: ptr
integer(c_size_t) :: len
ptr = c_loc(obj)
len = c_sizeof(obj)
ok = my%SendData(ptr,len)
end function
ifort now emits an error:
error #9023: The argument to C_LOC must not be polymorphic. [OBJ]
ptr = c_loc(obj)
While this function is polymorphic, in practice it is used only for a few simple structs containing scalars.
What is the best way to get this function "working" again, as well as it worked with previous compilers? I just need to get a C pointer to obj. Thanks for any help!
I have a code in C++ and I would like to call some functions in Fortran. I have the following function
Vector3d CWLiDAR__get_position(CWLiDAR* This)
{
return This->get_position();
}
There is a wrapper in Fortran:
module CWLiDAR_module
use, intrinsic :: ISO_C_Binding
implicit none
private
type CWLiDAR_type
private
type(C_ptr) :: object = C_NULL_ptr
end type CWLiDAR_type
interface
function C_CWLiDAR__get_position (this) result(pos) bind(C, name="CWLiDAR__get_position")
import
type(C_ptr), value :: this
real(C_double), intent(out), dimension(*) :: pos
end function C_CWLiDAR__get_position
end interface
interface get_position
module procedure CWLiDAR__get_position
end interface get_position
public :: get_position, CWLiDAR_type
contains
function CWLiDAR__get_position(this) result(pos)
type(CWLiDAR_type), intent(in) :: this
double precision, dimension(0:3) :: pos
pos = C_CWLiDAR__get_position(this%object)
end function CWLiDAR__get_position
end module CWLiDAR_module
However I am getting the following compilation error:
function C_CWLiDAR__get_position (this) result(pos) bind(C, name="CWL
1
Error: Assumed size array at (1) must be a dummy argument
function C_CWLiDAR__get_position (this) result(pos) bind(C, name="CWL
1
Error: Assumed size array at (1) must be a dummy argument
How can I pass a Vector3D to Fortran?
Functions which return arrays are NOT interoperable with C. You cannot call such a function from Fortran. At least not portably using bind(C).
If it was possible (but it isn't!) the syntax would have to be
interface
function C_CWLiDAR__get_position (this) result(pos) bind(C, name="CWLiDAR__get_position")
import
type(C_ptr), value :: this
real(C_double), dimension(some_number) :: pos
end function C_CWLiDAR__get_position
end interface
The compiler is complaining that neither intent, nor dimension(*) is allowed for function results in Fortran. That is the reason for the error message.
I am trying to pass a procedure pointer to a derived-type-bound-procedure
module mymodule
use mystoremodule
implicit none
private
type, abstract, public :: mytype
contains
procedure :: parse
end type mytype
contains
subroutine parse(self,mypointer)
implicit none
! Declaring Part
class(mytype) :: self
procedure(storing),pointer, intent(in) :: mypointer
integer :: myvalue
! Executing Part
myvalue = 42
call mypointer(myvalue)
end subroutine parse
end module mymodule
where storing is defined in another module/ derived type
module mystoremodule
implicit none
type, public :: storingtype
integer :: myvalue
contains
procedure, public :: storing
end type storingtype
contains
subroutine storing(self,myvalue)
! Declaring part
class(storingtype) :: self
integer, intent(in) :: myvalue
! Executing part
self%myvalue = myvalue
end subroutine SetExcitationOrder
end module mystoremodule
I call the procedure by
call mytypeobject%parse(storingtypeobject%storing)
With that i get a compiler error
The type of the actual argument differs from the type of the dummy argument.
I found out that the error comes from the procedure pointer not passing the dummy argument to the storing procedure (i didn't define anything as nopass). In all other cases the dummy argument gets passed automatically, why not here? It's not feasible for me to declare the dummy argument, as the object which the procedure uses changes.
Are there any solutions to my problem?
Well you are not passing there a procedure pointer. storingtypeobject%storing is not a procedure pointer, it is a binding to a type-bound procedure, not a pointer of any kind.
I wouldn't actually accept a pointer, but just a procedure argument in parse.
Something like:
subroutine parse(self,mypointer)
implicit none
! Declaring Part
class(mytype) :: self
procedure(storing), intent(in) :: myproc
integer :: myvalue
! Executing Part
myvalue = 42
call myproc(myvalue)
end subroutine parse
and
call mytypeobject%parse(storing_wrapper)
contains
subroutine storring_wrapper(myvalue)
integer, intent(in) :: myvalue
call storingtypeobject%storing(myvalue)
end subroutine
I think procedure pointers are mostly useful only if it can be changed somewhere. Not necessarily in parse but if you need to set it to some other target in some situations.
I have a problem with connecting Fortran program with C++ function.
My task is to call C++ function pointer from fortran, example:
// C++ function pointer
double* GetSplinePtr()
{
return sp;
}
I use iso_c_binding procedure and fortran interface.
For non-pointer function i usually use this declaration:
real(kind=c_double) function Name(x,y) bind(c, name='Name')
use iso_c_binding
implicit none
real(c_double), intent(in), value :: x,y
end function Name
But what should I use for function which returns a pointer?
Thanks!
As Ross comments, you must make the Fortran interface to return the C pointer and do the conversion to a Fortran pointer yourself.
interface
function GetSplinePtr() result(res) bind(C, name="GetSplinePtr")
use iso_c_binding
type(C_ptr) :: res
end function
end interface
In the calling code you have to call c_f_pointer() from the iso_c_binding module:
use iso_c_binding
type(c_ptr) :: p
real(c_double), pointer :: x
p = GetSplinePtr()
call c_f_pointer(p, x)
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 ?
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.