cfortranmixing

Fortran-C interoperativity basic example


I'm trying to learn how to call a Fortran function or subroutine from a C program and I made this simple example:

The Fortran function area.f90 is

function Area_Circle(r)

implicit none

real(kind(1.d0)) , intent(out):: Area_Circle
real(kind(1.d0)), intent(in) :: r

real(kind(1.d0)), parameter :: Pi = acos(-1.d0)

Area_Circle = Pi * r * r

end function Area_Circle

and the C main.c program

#include <stdio.h>

extern double Area_Circle_(double *r);

int main(int argc, char **argv){
    double r;

    printf("Enter the radius\n");
    scanf("%lf", &r);

    printf("The area is %lf\n", Area_Circle_(&r));

    return 0;
}

I tried to compile and build with the command

gcc -o app main.c area.f90 -lgfortran

and the exit is

area.f90:1:0:

 function Area_Circle(r)
 
Error: Symbol at (1) is not a DUMMY variable

What should I do to compile and run correctly this?

P.D.: I don't usually work in Fortran but some of my colleagues yes. For this reason I want to learn Fortran-C interoperativity.


Solution

  • There are multiple things that need to be addressed.

    Your Fortran function Area_Circle is incorrect: The function name's type aka its return type cannot have an intent.

    There is a module defined in the Fortran standard which makes interoperability of Fortran-C well-defined and portable: iso_c_binding. You should make use of it, e.g. note the bind(c) attribute and the real kind c_double.

    Fortran is case-insensitive s.t. you need to call it in all lowercase in your C program, i.e. area_circle instead of Area_Circle_. This behavior can be overridden by using bind(c, name="<some_name>").


    The Fortran file area.f90

    function Area_Circle(r) bind(c)
      use, intrinsic :: iso_c_binding
      implicit none
    
      real(c_double), intent(in) :: r
      real(c_double)             :: Area_Circle
    
      real(c_double), parameter :: PI = acos(-1.d0)
    
      Area_Circle = PI * r * r
    end function
    

    The C file main.c

    #include <stdio.h>
    
    extern double area_circle(double *r);
    
    int main(int argc, char **argv){
        double r;
    
        printf("Enter the radius\n");
        scanf("%lf", &r);
    
        printf("The area is %lf\n", area_circle(&r));
    
        return 0;
    }