cfortranfunction-pointersgfortranfortran-iso-c-binding

gfortran -fc-prototypes option for function pointers


The gfortran compiler has the interoperability option -fc-prototypes which generates the correct C-prototypes for interoperable functions (which have the BIND(C) attribute).

In the link it is written: "For function pointers, a pointer to a function returning int without an explicit argument list is generated. "

I tried it with some code that contains a BIND(C) subroutine that takes a function pointer to a subroutine with 2 integer arguments. Take the Fortran code in file test.F95:

subroutine test(pf) bind(c)

    use, intrinsic :: iso_c_binding
    implicit none
    type(c_funptr), intent(in), value :: pf
    
    abstract interface
        subroutine fproto(x, y) bind(c)
            use iso_c_binding, only: c_int
            integer(c_int), intent(in), value :: x, y
        end subroutine fproto
    end interface
    procedure(fproto), pointer :: f

    call c_f_procpointer(pf, f)
    call f(1, 2)
end subroutine test

Compile with: gfortran test.F95 -c -Wall -fc-prototypes > proto.h

This generates the C header file proto.h with the content:

#include <stddef.h>
#ifdef __cplusplus
#include <complex>
#define __GFORTRAN_FLOAT_COMPLEX std::complex<float>
#define __GFORTRAN_DOUBLE_COMPLEX std::complex<double>
#define __GFORTRAN_LONG_DOUBLE_COMPLEX std::complex<long double>
extern "C" {
#else
#define __GFORTRAN_FLOAT_COMPLEX float _Complex
#define __GFORTRAN_DOUBLE_COMPLEX double _Complex
#define __GFORTRAN_LONG_DOUBLE_COMPLEX long double _Complex
#endif

void f ();
void fproto (int x, int y);
void test (int (*pf)());

#ifdef __cplusplus
}
#endif

As you can see, the prototype of the subroutine fproto in the abstract interface is correct. But the correct C prototype of the argument of the test subroutine, i.e. of the function pointer should be:

void (*pf)(int, int)

But gfortran generates

int (*pf)()

This does not match at all. What is the point of this? Does that mean I should always pass function pointers to functions that return int? Or is this just (intentionally?) generated wrong?


Solution

  • gfortran is working as designed and documented (with the relevant piece of documentation actually quoted in the question in paragraph two!) here.

    The subroutine test takes a generic C function pointer as an argument. From the perspective of interoperability of that subroutine's interface, any function can be passed in. gfortran's interpretation of a matching function for any function is "a pointer to a function returning int without an explicit argument list".

    The association of a Fortran procedure pointer with the function pointer is an execution time activity. The prototype describes the characteristics of the function, which is a compile time concept.