Compilers supporting generation of C function prototypes

Among Fortran compilers, gfortran can be instructed to emit C function prototypes which can be put in a header file. Here’s how to do it with gfortran (see section Options for interoperability with other languages):

$ gfortran -fc-prototypes -fsyntax-only foo.f90 > foo.h

As an example, running the command above on the file

! foo.f90
module foo
  use, intrinsic :: iso_c_binding, only: c_float
  implicit none
contains
  real(c_float) function foo_sqr(x) bind(c)
    real(c_float), intent(in) :: x
    foo_sqr = x**2
  end function
  subroutine foo_print(x) bind(c)
    real(c_float), intent(in) :: x(:)
    write(*,*) x
  end subroutine
end module

will produce the header file:

#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 foo_print (const float *x);
float foo_sqr (const float *x);

#ifdef __cplusplus
}
#endif

For incompatible types, gfortran will issue a friendly warning.

Question: Do any other compiler vendors support this feature?

8 Likes

I’m not sure this works as expected. With my gfortran 15.1.0, the code:

program test

use iso_c_binding
implicit none

interface
  function my_c_function(string) bind(c)
    import :: c_int, c_char
    integer(c_int) my_c_function
    character(kind=c_char, len=*) string
  end function
end interface

end program

generates:

#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

int my_c_function (char *string);

#ifdef __cplusplus
}
#endif

I was expecting:

int my_c_function(CFI_cdesc_t *string);

Unless I’m still missing something about C/Fortran interoperability :slight_smile:

I agree with you. I also discovered some gaps in the coverage of this option - even in my original example, the assumed shape array x(:) should use a descriptor.

There was some work on the -fc-prototypes option in May 2025,

There are also a couple open issues in the GNU Bugzilla,

  • Bug 109322 - -fc-prototypes does not correctly translate INTEGER(KIND=C_SIZE_T), and other sizes
  • Bug 122245 - -fc-prototypes does not work with interfaces defined by a PROCEDURE statement
  • Bug 120220 - Lack of testing for -fc-prototypes and -fc-prototypes-external

Perhaps it would be worthwhile to open a new issue for assumed-shape arrays and assumed-length strings.

2 Likes

Code::Blocks25.03 BindTo can do it.