Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a FORTRAN subroutine from C

I am trying to call a FORTRAN function from C

My questions are:

  1. If fortRoutine is the name of my fortran subroutine, then I am calling this from C as fortRoutine_. If fortRoutine contains only one character array argument, then can I pass like this:

    fortRoutine_("I am in fortran");
    
  2. While calling FORTRAN subroutines, when should I use pass by value and when pass by reference?

As I am new to C, I do not have a clue about this. If possible, please suggest some good tutorial links as well.

like image 488
Kittu Avatar asked Nov 21 '11 06:11

Kittu


People also ask

How do I use subroutine in Fortran?

A Fortran function is similar to a mathematical function, which takes one or many parameters as inputs and returns a single output value. A Fortran subroutine is a block of code that performs some operation on the input variables, and as a result of calling the subroutine, the input variables are modified.

How do I call C from Fortran?

To actually call a C function from Fortran, first the interface must be declared. This is essentially equivalent to the C function prototype, and lets the compiler know about the number and type of the arguments, etc.

What is the command to execute subroutine in Fortran?

The CALL statement branches to the specified subroutine, executes the subroutine, and returns to the calling program after finishing the subroutine. CALL sub [([ ar [, ar ]])]

What is C in Fortran?

A most peculiar feature of Fortran 77 is its line structure, which is a carryover from the old days when programs were typed on punch cards. A punch card had 80 columns, and so does a line of Fortran code. A "c" in column 1 indicates a comment (similar to REM in Basic).


2 Answers

Of course this all depends on your FORTRAN Compiler, but generally speaking:

  1. No, you'll need to pass a hidden length argument for your string. Some compilers interleave these with the other parameters, directly after the string. Others, group all string length arguments at the end of the argument list.

    char str[11] = {0};
    fortranFunc_(str, sizeof(str) - 1);
    // remember that 'str' will need to be null terminated
    // and will be padding with spaces to fit the length
    // so for C passing strings to Fortran specify the length
    // less 1 so you can add a nul terminator, and on all strings
    // being filled in by FORTRAN, trim-end all spaces.
    
  2. Almost always it is pass by reference, but you can toggle this behavior using attributes on the dummy arguments on the FORTRAN side.

    int value = 10;
    fortranFunc_(&value);
    // INTEGER I
    

Here are some references, which are applicable based on various compilers:

  • FORTRAN/C interoperability
  • gfortran - Interoperability with C
  • Intel Fortran - Interoperability with C
  • The ISO_C_BINDING module
like image 25
user7116 Avatar answered Sep 27 '22 20:09

user7116


The way to do this now is to use the Fortran ISO C Binding on the Fortran side. This is part of the Fortran 2003 language standard and is available in many compilers; it is not specific to gcc. It has been described in many answers on this site. As part of the language standard, it is compiler and platform independent. And you do not need to know about the internal passing conventions of the compiler. The ISO C Binding, when used in the declaration of a Fortran subroutine or function, causes the Fortran compiler to use the C calling conventions so that that procedure can be directly called from C. You do not need to add hidden arguments or name mangle the Fortran subroutine name, i.e., no underscores. The name used by the linker comes from the "bind" option.

Strings are a difficult case because technically in C they are arrays of characters and you have to match this in the Fortran. You also have to deal with the different definitions of strings: C is null terminated, Fortran fixed length and padded with blanks. The example shows how this works. Numbers are easier. The only issue with arrays is that C is row-major and Fortran column-major so that multi-dimensional arrays are transposed.

int main ( void ) {

   char test [10] = "abcd";

   myfortsub (test);

   return 0;

}

and

subroutine myfortsub ( input_string ) bind ( C, name="myfortsub" )

   use iso_c_binding, only: C_CHAR, c_null_char
   implicit none

   character (kind=c_char, len=1), dimension (10), intent (in) :: input_string
   character (len=10) :: regular_string
   integer :: i

   regular_string = " "
   loop_string: do i=1, 10
      if ( input_string (i) == c_null_char ) then
         exit loop_string
      else
         regular_string (i:i) = input_string (i)
      end if
   end do loop_string

   write (*, *) ">", trim (regular_string), "<", len_trim (regular_string)

   return

end subroutine myfortsub

You compile the C to an object file and use gfortran to compile the fortran and link both:

gcc-mp-4.6   \
         -c  \
         test_fortsub.c

gfortran-mp-4.6   \
     test_fortsub.o  \
     myfortsub.f90  \
     -o test_fortsub.exe

Output is:

 >abcd<           4
like image 54
M. S. B. Avatar answered Sep 27 '22 20:09

M. S. B.