From: bobp@msi.com (Bob Pitha)
Subject: Re: calling a Fortran subroutine from a C program
Followup-To: comp.lang.c,comp.lang.fortran
Organization: Molecular Simulations, Inc.
Date: Fri, 22 Jan 1993 13:07:43 GMT
X-Newsreader: TIN [version 1.1 PL8]
X-Posted-From: phoenix.msi.com
NNTP-Posting-Host: sol.ctr.columbia.edu

Scott White (swhite@mathcs.emory.edu) wrote:
: Can someone please tell me how to call a Fortran subroutine from a C program?
: The environment is sun4, OS 4.1.2.

Sure, this isn't really that hard as long as you keep a few basic issues in
mind:

1) Function names: Fortran is a case-insensitive language, so typically
 Fortran compilers convert names to entirely upper- or lower-case.  The
 sun compiler does lowercase; it also appends an underscore to the end
 of the function name.  Thus, a Fortran subroutine named MyFortranSub
 would be exported to the linker as myfortransub_.  There is an option
 for the compiler to preserve case, I think it's -U, but I'll assume
 you're not using it.

2) Arguments: Fortran always expects pointers in its argument list.  So
 always pass an address from C.

3) Arrays: There are a couple of insidious issues with arrays: first,
 remember that C arrays start from 0, and Fortran from 1.  So if you
 assign a value in C to element [3], you should access it in the Fortran
 subroutine as element (4).  Alternately, declare your arrays in Fortran
 to explicitly start from 0.  I don't like to do that, but you can inf
 you want.
   Multi-dimensional arrays can be a headache, too, because it's easy to
 get the order of the subscripts mixed up.  C arrays are stored such that
 the second subscript varies faster than the first: x[2][2] is stored in
 memory in the following order: x[0][0]; x[0][1]; x[1][0]; x[1][1].  It's
 exactly the opposite in Fortran; the array x (2,2) is stored as: x(1,1);
 x(2,1); x(1,2); x(2,2).  So remember to reverse the order of your
 subscripts when accessing multidimenstional arrays.

4) Character arrays: For each character array in the argument list, there
 should be a long int at the end of the argument list specifying the
 *declared* length of the array - that is, how much space is allocated
 for it.  Since Fortran blank-fills character arrays, this number will
 specify how many places to fill.  If you have more than one character
 array in the argument list, the length arguments should be in the same
 order as the character arguments.

  So now, here's a mocked-up example of how to do this.  I'll try to keep
it short but still touch on each concept to some extent:

  (in C):

    int      int_arg;
    int      int_array [3];
    int      int_matrix [4][3];
    float    float_arg;
    char     string [12];

    strcpy (string, "test");
    int_array [1] = 37;
    int_matrix [2][1] = 54;
    myfortransub_ (&int_arg, &float_arg, int_array, int_matrix, string,
                   (long) strlen (string));


 (and now the Fortran part)

      subroutine MyFortranSub (int_arg, float_arg, int_array,
     +                         int_matrix, string)
      integer       int_arg
      real          float_arg
      integer       int_array (3)
      integer       int_matrix (3, 4)
      character*(*) string

      int_array (2) should be 37
      int_matrix (2, 3) should be 54
      string should be "test"

: Also, the called Fortran routine takes variables which are arrays as 
: parameters.  And, I looked and saw that the subscripts start at 1, whereas in
: C they start at zero.  That's no problem is it (an address is an address):

 No, it's no problem, assuming you remember it everywhere.  It only makes
it a bit easier to make one of those annoying off-by-one subscript errors!

: /* .c file */
: 	int num[100];
: 	double zeta[100];

: 	foo(num, zeta);


: /* .f file */
: 	subroutine foo(number, gamma)
: 	integer*4 number(100)
: 	real*8    gamma(100)

: 	/* program proceeds to manipulate values in the arrays, with subscripts
: 		1 through 100, not 0 through 99 */

  As said above, in your C file you should call foo_, not foo.

: Finally, if the Fortran subroutine changes the values in gamma, the changes
: show up when we return to the C program, right?

  Absolutely.  In both the C function and the Fortran subroutine, gamma
refers to the same 400 bytes of memory.

  There's a section in the Sun FORTRAN User's Guide that talks about
C/Fortran interfaces.  If you have the manual, it's worth reading.  There
are a lot of little picky issues I didn't touch on - and probably won't
come up if you're doing something as simple as the foo function you use
as an example.

  Good luck!

-----------------------------------------------------------------------
Bob Pitha                      Molecular Simulations Inc.
bobp@msi.com                   16 New England Executive Park
(617) 229-9800 x242            Burlington, MA 01803-5297