Problem calling a dummy callback from Fortran

Problem calling a dummy callback from Fortran

I have a problem calling a dummy callback from Fortran.

We have a C++ program which calls Fortran code, EQCONTOUR.
It passes a function pointer (FCALL) when calling this subroutine.
The purpose is to provide a callback function that the Fortran can call back in the C++ world to echo progress, etc.
This all works fine and here is the code:

EQCONTOUR uses this module:

      module GUI_OLI
        implicit none
        save
        interface
          integer function GUI_FCALL(TEMP,PRES,IPT,JPT,KERR)
            REAL*8 , intent(in)  :: TEMP, PRES
            INTEGER, intent(in)  :: IPT, JPT
            INTEGER, intent(out) :: KERR
          end function
        end interface
        pointer (p_GUI_FCALL, GUI_FCALL)
      end module GUI_OLI

Here is EQCONTOUR:

      SUBROUTINE EQCONTOUR(FCALL)
      USE GUI_OLI
      IMPLICIT NONE
      INTEGER    :: FCALL

      p_GUI_FCALL = FCALL
...
      IF(GUI_FCALL(TEMP,PRES,IT,IP,KERR) == 0) THEN
...
      RETURN
      END

This works fine when EQCONTOUR is called from C++.

The problem comes when I want to test calling EQCONTOUR from Fortran.
Here is my code:

      PROGRAM TEST
      IMPLICIT NONE
      INTEGER, EXTERNAL :: FCALL
!
      call EQCONTOUR(FCALL)
      END
! dummy FCALL
      integer function FCALL(TEMP,PRES,IPT,JPT,KERR)
        REAL*8 , intent(in)  :: TEMP, PRES
        INTEGER, intent(in)  :: IPT, JPT
        INTEGER, intent(out) :: KERR
        FCALL = 1
        KERR = 0
      end function

When I try to call from Fortran as above, I get an access violation on the
IF(GUI_FCALL(... line.

I'm not sure why.

2 Beiträge / 0 neu
Letzter Beitrag
Nähere Informationen zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.
Bild des Benutzers Steve Lionel (Intel)

You've left out some critical lines - such as what I suspect is:

POINTER (p_GUI_FCALL, GUI_FCALL) in EQCONTOUR

The way you have coded EQCONTOUR, it is expecting an integer by reference containing the address of the callback routine. This isn't consistent with simply passing the routine has you have in your test program.

Try this:

PROGRAM TEST
IMPLICIT NONE
INTEGER, EXTERNAL :: FCALL
INTEGER :: p_FCALL
p_FCALL = LOC(FCALL)
!
call EQCONTOUR(p_FCALL)
END

I will also comment that your code will fail if built as a 64-bit program because you are assuming 32-bit addresses. I'd prefer to see this rewritten using procedure pointers and the C interoperability features, but you could simply change the INTEGER :: FCALL in EQCONTOUR to INTEGER(INT_PTR_KIND()) :: FCALL and similarly the declaration of p_FCALL I added above. The C code would need to make sure it is passing a pointer and not an int.

Steve

Melden Sie sich an, um einen Kommentar zu hinterlassen.