From: hwrvo@kato.lahabra.chevron.com (W.R. Volz)
Newsgroups: comp.lang.c,comp.lang.fortran
Subject: Re: calling a Fortran subroutine from a C program
Date: 22 Jan 93 01:12:29 GMT
Followup-To: comp.lang.c
Organization: Chevron Oil Field Research Company

In article <1jmqdaINN11g@mudhoney.mathcs.emory.edu>, swhite@mathcs.emory.edu (Scott White) writes:
|> Can someone please tell me how to call a Fortran subroutine from a C program?
|> The environment is sun4, OS 4.1.2.
|> 
|> 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):
That is correct, it doesn't matter where the arrays start in fortran but
in C they sill always start at 0.
|> 
|> /* .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 */
|> 
|> 
|> Finally, if the Fortran subroutine changes the values in gamma, the changes
|> show up when we return to the C program, right?
Yes.
|> 
|> Your gracious help is deeply appreciated.
|> 
Some other things to think about: If you wanted to pass the number of
elements to process:

 int n = 100;
 foo(num,zeta,&n);

 subroutine foo(num,zeta,n)
 ...
Note that fortran always expects the address of something, C (strickly
speaking always passes things by the value of the somethings. If you didn't
include the &n in the c call to foo, the fortran foo would look for the
number of elements at addess 100 and probably abort on the call. This
is sometimes difficult to track down.

If you are passing character strings, all bets are off. It depends heavily
on what fortran compiler you are using and how they handle character
arrays. Sometimes the fortran arguement list is modified to include
the length of the character string, so there may be extra arguments 
sometwhere in the list. What I did is to write a short fortran routine
that expects a byte or integer*1 array:

 subroutine c_str_to_for(cstr,fstr)
 byte cstr(*)
 character*(*) fstr
 i = 1
c set entire fortran string to blanks to handle shorter strings
 fstr = ' '
c don't overflow the fortran string and loop until the c null characte appears.
 while(i .le. len(fstr).and.cstr(i) .ne. 0)
c copy character and increment
  fstr(i:i) = char(cstr(i))
  i = i + 1
 end do
c or some such thing. This may not be completely correct, it's from memory.
 return

and use this to convert c strings to fortran strings.
so 
 char *cstr = "This is a C string";
 foo(str);

 subroutine foo(cstr)
 byte cstr(*)
 character*100 fstr
 c_str_to_for(cstr,fsrt);
 write(6,*) fstr
 return
 end

Also some compilers change the name of the fortran routine as seen
by the linker. The MIPS compiler is notorius for this. It adds an
underscore on the end of the name and changes all characters in the
name to lower case. So on that compiler you'd do foo_(cstr); instead..

All in all, calling fortran from c and vice-versa can be a total bitch.

Have fun.
s

-- 

======================
Bill Volz
Chevron Petroleum Technology Co.
Earth Model/Interpretation & Analysis Division.
P.O. Box 446, La Habra, CA 90633-0446
Phone: (310) 694-9340 Fax: (310) 694-7063
Newsgroups: comp.lang.c