Fortran-C++ interoperability: Passing array via void pointer
Asked Answered
G

0

7

I roughly have the following situation. I have a C++ function which is called from Fortran code and takes a function pointer and a void pointer as arguments like this

int STDCALL FORTRAN_NAME(CPPFunction, CPPFUNCTION)(
    int (*userFunction)(const int *object,
                        const void *userFunctionUserData),
    const void *userData)
{
  // ...
    int index;
    int result;
  // ...
    result = userFunction(&index, userData);
  // ...
}

This is called from Fortran like this

! ...
DOUBLE PRECISION, ALLOCATABLE :: data(:,:)
INTEGER :: n, result

! ...

ALLOCATE(data(3,n)); data = 0.0

! ... fill data with something

result = CPPFUNCTION(FORTRANFUNCTION, data)
! ...

The Fortran function which I want to pass via the function pointer looks like

INTEGER FUNCTION FORTRANFUNCTION(idx, data)
IMPLICIT NONE

INTEGER, INTENT(IN) :: idx
DOUBLE PRECISION, INTENT(IN) :: data(*)
INTEGER :: i, offset

offset = 3 * (idx - 1)
WRITE(*,*) 'data(offset + 1) = ', data(offset + 1)
WRITE(*,*) 'data(offset + 2) = ', data(offset + 2)
WRITE(*,*) 'data(offset + 3) = ', data(offset + 3)

END FUNCTION FORTRANFUNCTION

If I start the whole thing CPPFunction seems to be correctly called, it calls FORTRANFUNCTION and I get an exception code

c0000005 ACCESS_VIOLATION

exactly in the line in FORTRANFUNCTION where the first access to the array data is done.

WRITE(*,*) 'data(offset + 1) = ', data(offset + 1)

Can somebody tell me where my mistake is? I should also mention that the C++-function is not mine. It is not impossible to change it but it would affect lots of other code. The Fortan part is completely under my control and I can do what I want with it.

Thank you.

Gabionade answered 19/12, 2014 at 10:16 Comment(10)
Shouldn't the first parameter be just int object?Debidebilitate
I changed the tag to fortran to get you more attention, but, for the record, the OP originally requested Fortran 90.Sorption
@Anton Savin I thought that since Fortran passes its variables by reference, I MUST give addresses in the calling C++-program, but this is the first time I use C++ and Fortran together, so I am not sure.Gabionade
@Gabionade Yes, you should pass addresses unless the FORTRAN_NAME macro does something very strange.Sorption
The calling convention for the top level C++ function appears to be set to stdcall, presumably to suit the calling convention of your Fortran compiler (which compiler?). I don't see a similar calling convention qualification for the calling convention of the function pointer argument in the C++ code.Fetal
I have a very limited experience mixing C++ and fortran (I'm on the C++ side of a mixed project), and looking at my examples, I see we also use extern "C" { ... } and __stdcall to wrap all functions and global vars exposed to fortran code. I think the arguments you receive are ok, I don't know about the return value, but may be the error is related to calling conventions.Magna
@Fetal The compiler is IFORT 11.1.Gabionade
I'm building for x64 architecture, so the calling convention should be x64 calling convention, right?Gabionade
Do you have to stick to F90? If not, I'd suggest to give the ISO_C_Binding from F2003 a try.Streamway
I don't know any reason to set stdcall in X64 development, although it may make no difference (as it would in 32-bit mode). ifort has an option to change from default to stdcall. iso_c_binding obviously is preferable and covered by all maintained compilers, but I don't know that compatibility with void * is assured. Is void * really appropriate?Bailsman

© 2022 - 2024 — McMap. All rights reserved.