In C++, I allocate an array of S. In Fortran, I want to access elements of this array. How can I do this?
C++:
struct S {double a; double b;};
S *arrayOfS;
arrayOfS = (S *)new S[123]; // allocate
Fortran 2003:
USE ISO_C_Binding
TYPE, BIND(C) :: SFortran
REAL(c_double) :: a,b
END TYPE SFortran
S and SFortran should now be interoperable, but I also need to have a way to access the elements of the array declared in C++. I'd like to have SC(5)%a in Fortran correspond to arrayOfS[4].a in C++. How do I declare and set the proper value for Fortran array SC that will have this access?
You could:
1) pass the C++ array to a Fortran BIND(C) procedure that takes an appropriate array argument.
SUBROUTINE proc(array) BIND(C, NAME='proc')
...
TYPE(SFortran) :: array(*)
WIth this approach you might also want to pass the size of the array across and make the array argument explicit shape.
b) have the array pointer as an extern "C" global on the C++ side, and then interoperate through a Fortran module variable with BIND(C).
MODULE some_module
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR, C_F_POINTER
...
TYPE(C_PTR), BIND(C, NAME='arrayOfS') :: array_ptr
...
! In a procedure in the module...
TYPE(SFortran), POINTER :: array(:)
CALL C_F_POINTER(array_ptr, array, [123])
Again it might suit to have size of the array available separately to avoid hard coding it in the C_F_POINTER reference.
Which approach is best depends on your requirements!
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 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.)
I am converting some of our Fortran library code into C so that we finally have C functions with Fortran wrappers around it. We are using Fortran 95.
What is the preferred way to handle allocatable arrays?
Can I pass an allocatable array to a C function and malloc it inside the C function?
(The C function knows the size to be malloc'ed)
In the fortran program, can I deallocate something that was malloced in a C function?
So finally either the client fortran application deallocates the array or is required to call a C function that frees the memory.
A small example or a link to one would be highly appreciated.
In Fortran 95 you can't "pass" allocatable arrays as an allocatable thing to anything, including Fortran procedures.
In Fortran 2003, the C function can malloc storage for the array, and then return that to the Fortran side as a C_PTR from the ISO_C_BINDING intrinsic module. The storage pointed to by the C_PTR can then be accessed using a Fortran POINTER and the C_F_POINTER procedure from the ISO_C_BINDING module.
To free the storage for the array, the Fortran side would again call into a C procedure, passing the C_PTR, which the C function then uses in a call to free.
#include "stdlib.h"
int *create_storage()
{
/* Array of four integers. */
return malloc(sizeof(int) * 4);
}
void destroy_storage(int *ptr)
{
free(ptr);
}
PROGRAM fortran_side
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR, C_F_POINTER, C_INT
IMPLICIT NONE
INTERFACE
FUNCTION create_storage() BIND(C, NAME='create_storage')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
IMPLICIT NONE
TYPE(C_PTR) :: create_storage
END FUNCTION create_storage
SUBROUTINE destroy_storage(p) BIND(C, NAME='destroy_storage')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
IMPLICIT NONE
TYPE(C_PTR), INTENT(IN), VALUE :: p
END SUBROUTINE destroy_storage
END INTERFACE
TYPE(C_PTR) :: p
INTEGER(C_INT), POINTER :: array(:)
!****
p = create_storage()
CALL C_F_POINTER(p, array, [4]) ! 4 is the array size.
! Work with array...
CALL destroy_storage(p)
END PROGRAM fortran_side
In Fortran 201X, C header files and functions may be provided to allow C to work directly with Fortran allocatable variables.
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.