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.

CKE
  • 1,533
  • 19
  • 18
  • 29
user26756
  • 233
  • 1
  • 9
  • 1
    Shouldn't the first parameter be just `int object`? – Anton Savin Dec 19 '14 at 10:22
  • I changed the tag to `fortran` to get you more attention, but, for the record, the OP originally requested Fortran 90. – Vladimir F Героям слава Dec 19 '14 at 10:28
  • @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. – user26756 Dec 19 '14 at 10:40
  • @user26756 Yes, you should pass addresses unless the FORTRAN_NAME macro does something very strange. – Vladimir F Героям слава Dec 19 '14 at 12:08
  • 1
    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. – IanH Dec 19 '14 at 12:16
  • 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. – Zaskar Dec 19 '14 at 12:22
  • @IanH The compiler is IFORT 11.1. – user26756 Dec 19 '14 at 14:57
  • I'm building for x64 architecture, so the calling convention should be x64 calling convention, right? – user26756 Dec 19 '14 at 15:26
  • 1
    Do you have to stick to F90? If not, I'd suggest to give the ISO_C_Binding from F2003 a try. – haraldkl Sep 05 '15 at 06:49
  • 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? – tim18 Sep 02 '18 at 11:29

0 Answers0