Click here to Skip to main content
13,095,663 members (52,098 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as


1 bookmarked
Posted 11 Sep 2012

C / Fortran Interoperability With External Fortran Function passing and Struct type arguments

, 11 Sep 2012
Rate this:
Please Sign up or sign in to vote.
Showing how to pass a Fortran function into C and using a compatible C-Struct as argument.


This example shows off many features of Fortran / C interoperability, including:

  • the ISO_C_BINDING since Fortran 2003, allowing C-Fortran working together smoothly.
  • Interoperate between C struct and Fortran Derived Type.
  • Use of C "void * p" parameter.
  • Passing Fortran function as an Argument to a C function.
  • Use of Fortran Interfaces and Modules.
  • Abstract C function, Abstract Fortran function.
  • Using C's Struct or Fortran's Derived Type as arguments.


A brief description of the example is that there is a function called gsl_UVMIF(). One of its parameters is another function called with interface fnExt(double, void*). In actual usage, fnExt() is an abstract representation of Fortran functions which can be any of the following:

  • f1(x, dpar3)
  • f2(x, dpar5)
  • f3(x, dpar10)

... where x is double precision, and dpar3, dpar5, dpar10 and whatever are a list of Fortran double precision parameters defined as Derived types, analogous to C-struct.

From the highest level, there is a Fortran driver program or code that will call C's gsl_UVMIF(), via a Fortran interface fgsl_UVMIF(). The gsl_UVMIF() will call Fortran functions of the form fnExt(x, {parameters}).

Using the code

The code is given as follows. At the core of the usage is the following C code.

#include "head.h"
void gsl_UVMIF(double (*fnExt)(double, void*) , dPar3 *adPar3, double blah, ....) {
    .. fnExt            // using function
    .. *adPar3       // using variables

In the header file head.h, define the C-struct which must have an exact correspondence to Fortran Derived Type. Note there is a 3-parameter and 10-parameter structure. The prototype of the function is also declared.

extern "C"{
    // Structure of 3 parameter values
    typedef struct {
        double a,b,c;
    } dPar3;
    // Structure of 10 parameter values
    typedef struct {
        double a,b,c,d,e, f,g,h,i,j;
    } dPar10;

    __declspec(dllexport) void gsl_UVMIF(double (*fnExt)(double, void*) , dPar3 *adPar3, double blah);

The details of the function fnExt are defined on the Fortran side. But before doing that, we also need to define the list of parameters as Fortran Derived Type which must exactly match the C struct data type. Define the structure in a module of its own.

MODULE extStructures
    implicit none
    TYPE, BIND(C) :: dPar3
        REAL(C_DOUBLE) :: a,b,c
    END TYPE dPar3
    TYPE, BIND(C) :: dPar10
        REAL(C_DOUBLE) :: a,b,c,d,e, f,g,h,i,j
    END TYPE dPar3
END MODULE extStructures

Define the Fortran interface called fgsl_UVMIF() which connects directly to gsl_UVMIF(). It uses the parameter structure dPar3 defined in extStructures above.

MODULE mod_f90
    USE extStructures    ! where parameter structures are defined above.
    implicit none

        SUBROUTINE fgsl_UVMIF(fnExt , param3, blah, ....)  BIND(C, NAME='gsl_UVMIF') 
            USE, INTRINSIC :: ISO_C_BINDING     ! New Fortran 2003 standard
            USE extStructures
            IMPLICIT NONE 

            REAL(C_DOUBLE) :: fnExt           ! External Fortran function defined by user.
            EXTERNAL fnExt

            TYPE(dPar3) :: param3             ! parameter with 3 doubles struct.
END MODULE mod_f90

Here is one example of the Fortran function with three parameters. This code is defined outside any Fortran MODULE or PROGRAM. So the list of parameters, dpar, is passed in as a Fortran structure.

    USE, INTRINSIC :: ISO_C_BINDING     ! New Fortran 2003 standard
    use mod_f90, only : dPar3
    TYPE (dPar3) dpar
    Fext_dUVMIF = dPar%a*X*X + dPar%b*X + dPar%c     ! y = ax^2 + bx + c

The main Fortran driver code is below.

    USE mod_f90, only : fgsl_UVMIF        
    real(C_DOUBLE) :: Fext_dUVMIF      ! External functions
    external Fext_dUVMIF
    TYPE(dPar3) :: param3              ! variables of the ext function

    param3%a = 1.0d0
    param3%b = -4.0d0
    param3%c = 5.0d0
    CALL fgsl_UVMIF(Fext_dUVMIF, param3, blah, ...) 

The call stack is roughly main() -> fgsl_UVMIF() -> gsl_UVMIF() -> *fnExt() -> Fext_dUVMIF().

Points of Interest 

Key lessons were passing in a Fortran function as an argument of another C function, which is called within another Fortran code. Also passing a list of parameters in C Struct format using it's Fortran equivalent of Derived Type.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

c chee
Australia Australia
No Biography provided

You may also be interested in...


Comments and Discussions

QuestionInteresting, but a small typographic error. Pin
Rick York13-Sep-12 19:43
memberRick York13-Sep-12 19:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170813.1 | Last Updated 11 Sep 2012
Article Copyright 2012 by c chee
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid