calling c from f77: here is summary of responses

Liz Heller lizh at athena.UUCP
Tue Dec 18 03:45:37 AEST 1984


*** Summary of responses to my request for advice on calling c from f77 ***

Since there seems to be a lot of interest in calling c from f77, I'm
posting the responses I got.  There is also an article in Tektronix's 
current Technology Report (November/December 1984) on how to do it.

Liz

-----------------------------------------------------------------------------
From: tektronix!reed!joey
Organization: Reed College, Portland, Oregon

	Hi, I've done some f77 to C interfacing.  What you suggest will
work fine.  You just have to remember that all calls are call by
address, so do lots of indirection.  All f77 passes are double *, or
int *.  Also, f77 function names have an _ on the end, so if you call x
from f77 that will be x_ in C.  One other useful thing is that the f77
compiler knows how to compile C programs, so you don't have to think to
hard about what needs to be done to get them all compiled together
right.  Like:

	f77 -O -o foobar foo.o bar.f bletch.s interface.c -lplot

And, although fortran is pretty horrible, f77 isn't to bad.  If
you have the desire to convert the fortran to C, you can try
using struct to change the fortran to ratfor and then massage
the ratfor until it becomes C.  Anyway, hope I didn't muddy the
waters too much.

	-joey
	Joe Pruett
	...!tektronix!reed!joey

----------------------------------------------------------------------------

From: tektronix!ihnp4!rlgvax!guy

That's exactly how the UNIX system calls are made available in "libU77";
an interface routine to convert calling sequences is wrapped around the
bare routine.  I don't think there's any other way.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy


----------------------------------------------------------------------------
From: tektronix!decvax!mulga!lizs:munnari

	Over the last year or so, I have written several c routines to enable a
large f77 package, running under 4.2BSD, to gain access to some of the c
library routines in /lib/libc.a .  The following is a summary of some of my
experiences.

	The only documentation I had available (or indeed that I am aware of)
consisted of Feldman and Weinberger's description of the f77 compiler (" A
Portable Fortran 77 Compiler ") and the on-line manual.  Nearly all of the
hassles I encountered stemmed from the f77 compiler's extremely irritating
procedure of appending an underscore to all user-defined global symbols.  The
main problems were:

1.  Many of the c routines for the package were written by different people,
some of whom had appended underscores liberally to all sorts of variables.  I
have learned from bitter experience that it is extremely inadvisable to do this
to any external or global variables, except those that need to be accessed
directly by fortran programs or subroutines.

   The following experience will illustrate the problems that this can cause.
At one time I added an f77 subroutine called "longname" to the package I was
developing.  This subroutine worked perfectly when linked to a short program
designed to test it, but if I linked it into the package, it would cause a
mysterious crash whenever it was called.  After I had practically torn my hair
out for a couple of days, it finally dawned on me that the crash might be due
to an ambiguous symbol definition, and by grep-ing all the sources I eventually
found a global symbol called "longname_" in one of the c routines that someone
else had written.

Apparently the link editor, ld, gives no warning of multiply defined global
symbols, and was happily resolving the undefined f77 external reference
"longname" with the c-defined global symbol "longname_".  This bug is
particularly insidious and difficult to track down, because its cause is so far
removed from the code where it seems to be occurring.

2.  If the name of a c procedure did not end in an underscore, until very
recently I did not know any way of calling it directly from a fortran program
( I do now - I have included brief details below).  This was very irritating, 
since many of the library routines I wanted to use could otherwise have been
called directly from the fortran without requiring any manipulation of
arguments at all.


	Most of the time, I implemented calls to the c library routines that I
wanted in precisely the way that you have proposed ( except that if the fortran
program "x" calls a function or subroutine called "y", which is to be written
in c, then the c procedure has to be called "y_" rather than "y" ).  However, I
have since found out that the fortran library, libU77, already contains some
procedures for accessing many of the c library routines directly.  So, before
you write any procedures for calling c library routines from f77 programs, I
suggest you first check section 3f of the on-line manual to see if the routine
you want is not already available.  Unfortunately, for some reason which I
cannot fathom, some of the libU77 routines apparently do not make all the
facilities of the corresponding libc routine available to the calling program
( Here I am thinking particularly of the libU77 function  signal , which would
not seem to let me catch SIGTSTP signals, among others, when I tried to use it).

	For c routines whose formal parameters are already in an appropriate
form for the routine to be called directly from fortran programs, I have very
recently thought of a way to get round the problem of appended underscores,
provided the routine's name forms a valid f77 identifier, and is at least two
characters long.  Suppose the c routine that you want to call is named "xyz".
Then, when you want to call the routine from your fortran program, you leave
off the last letter of the routine's name, so that the call statement becomes
" call xy ".  Next, compile the fortran program into an object module, which
will contain the string "xy_" in its string table, as the name of an undefined
external reference.  In order to link the program to the required c routine,
this string must be replaced with the routine's correct name of "xyz".  It
should not be difficult to write a short program for processing the object
module and making the appropriate substitution.  To do this properly, you would
need to know something about the location and format of string tables in object
modules, a topic on which I have been unable to find any documentation
whatsoever.   However, I have written a short pascal program which, if supplied
with a string of the form "xy....wz", will replace EVERY occurrence of the
string "xy....w_" in a specified object module with this supplied string.
Except in the unlikely event that the string "xy....z_" occurs by chance
somewhere else in the object module besides the string table, this program will
do the job. 

Once the object module has been processed by the string substituting program,
you then use the link editor, ld, to link it and obtain the final executable
file.  Although this idea has worked perfectly well on the short test programs
I have tried it on, it may require too much development to make its application
to more substantial programs worthwile.  Nevertheless, if you would like a copy
of my pascal program for processing the object files, please let me know and I
will mail it to you.

	I am sorry to have raved on at such length, particularly if you were
already aware of most of this information.  However, if you have any queries,
you can reach me here until next February.

						David Wilson 

------------------------------------------------------------------------------

From: tektronix!hplabs!oblio!jon

-------
Talk to Dr. Adnan Onart (tekecs!adnano).  I don't know his extension offhand.
He's document the calling sequence compatability for the F77 to C GKS
library.

				Jon Steinhart (ex-Tekker)

-----------------------------------------------------------------------------

From: tektronix!decvax!decwrl!amd!cae780!gordon

The only real problem with f77 to c is that f77 is call by address, so
the c routine must be able to handle that.  If not, your intermediate
routine approach would appear to be the only reasonable fix.  I have
had no problem with it -- but I do have control over the c code, a
"slight" advantage.

---------------------------------------------------------------------------

From: tektronix!ihnp4!oddjob!paul
Organization: University of Chicago, Department of Astronomy and Astrophysics

In article <athena.100> you write:
>Has anyone had experience with calling c routines from fortran 77 on 4.2
>unix? Know of any articles, pitfalls? The way I'm thinking of doing it
>is as follows (fortran 77 program "x" really wants to call c routine "z",
>but instead calls c routine "y"):
>
>	"x"
>	  call to "y"
>
>	"y"
>	  manipulate arguments for call to "z"
>	  call to "z"
>
>	"z"
>	  ...
>
>The c routines are fixed - I can't change the way they're called. Anyone
>know a better way to do this?
>
>Liz Heller


	I've had lots of experience doing this, and the way you describe is
the only way to do it.  I usually call the routine you call "y" "z_" for the
following reason:  the c compiler prepends the name of any routine with an 
underscore, while fortran prepends and appends.  Thus, the routine "z_", when
compiled by cc, turns out to have the name "_z_", which is exactly what
f77 is looking for when it executes "call z(...)".  The other thing to
remember is that fortran is all call by address, while c is all call by
value.  All of the variables in the parameter list in z_ should be declared as
pointers to the appropiate type.  So for instance, if z accepts an int in the
calling list, then z_ should be written:

	z_(a)
	int *a;
	{
		int b;
		b = *a;
		z(b);
	}

The only other pitfall is that multi-dimensional arrays in c should have the
indices reversed from the ones in fortran.  If x is used in fortran as

	x(i,j,k)

then in c the same element is

	x[k][j][i]

I call c routines from fortran (and vice versa) routinely.  It's nice to get
some of the features of c in UNIX that would otherwise be unavailable in
fortran.  Hope this helps.  If you need any more help, feel free to send me
mail.


				Paul Schinder
				Astronomy and Astrophysics Center
				University of Chicago
				uucp: ..!ihnp4!oddjob!paul

Relay-Version: version B 2.10.2 (Tek) 9/12/84; site athena.UUCP
Posting-Version: version B 2.10.2 9/17/84; site hao.UUCP
Path: athena!teklds!tektronix!hplabs!hpda!fortune!amdcad!decwrl!decvax!ittvax!dcdwest!sdcsvax!sdcrdcf!trwrba!cepu!hao!woods
From: woods at hao.UUCP (Greg "Bucket" Woods)
Newsgroups: net.lang.f77,net.lang.c
Subject: Re: calling c routines from fortran
Message-ID: <1265 at hao.UUCP>
Date: 19 Nov 84 18:24:18 GMT
Date-Received: 22 Nov 84 15:05:11 GMT
References: <100 at athena.UUCP>
Organization: High Altitude Obs./NCAR, Boulder CO
Lines: 36

> Has anyone had experience with calling c routines from fortran 77 on 4.2
> unix? Know of any articles, pitfalls? 

   Unfortunately, due to the fact that F77 insists on appending a "_" to all
of it's routine names, you cannot call *any* C routine from F77 unless it's
name ends in "_". In addition to that, all F77 arguments are pointers, so you
can't even call a routine whose name ends in "_" if it is expecting any non-
pointer arguments (usually the case in C). Therefore, the only way to do this 
is the following (which is what I gather Liz was suggesting) (suppose you want
to call routine "z" which returns an int and has one int argument):

....
      iretvl=iz(intvar)
....

int iz_(intvar)  int *intvar;
{
int z(); /* this declaration not necessary for int functions */
   return(z(*intvar));
}

  I know this is kludgy, but I use it all the time and it works fine. It's the
only thing you can do (well, maybe you could write the intermediate routine
in assembly, but I doubt if you could gain much efficiency that way, and it's
a lot more confusing).
   For a reference, see the paper "A Portable Fortran 77 Compiler" by S. I. 
Feldman and P.J. Weinberger, which, among other places, appears in the "Volume
2C" manual which came with our 4.2BSD manuals.

--Greg "FORTRAN hacker" Woods
-- 
{ucbvax!hplabs | allegra!nbires | decvax!stcvax | harpo!seismo | ihnp4!stcvax}
       		        !hao!woods
   
     "...once in a while you can get shown the light
         in the strangest of places if you look at it right..."

Relay-Version: version B 2.10.2 (Tek) 9/12/84; site athena.UUCP
Posting-Version: version B 2.10.2 9/18/84; site brl-tgr.ARPA
Path: athena!teklds!tektronix!hplabs!hpda!fortune!amdcad!decwrl!decvax!genrad!mit-eddie!godot!harvard!seismo!brl-tgr!gwyn
From: gwyn at brl-tgr.ARPA (Doug Gwyn <gwyn>)
Newsgroups: net.lang.f77,net.lang.c
Subject: Re: calling c routines from fortran
Message-ID: <5943 at brl-tgr.ARPA>
Date: 20 Nov 84 17:33:50 GMT
Date-Received: 24 Nov 84 07:08:19 GMT
References: <100 at athena.UUCP> <1265 at hao.UUCP>
Organization: Ballistic Research Lab
Lines: 2

Also watch out for interference with the F77 run-time system if the
called C routines do any I/O.

Relay-Version: version B 2.10.2 (Tek) 9/12/84; site athena.UUCP
Posting-Version: version B 2.10.2 (MU) 9/23/84; site munnari.OZ
Path: athena!teklds!tektronix!hplabs!pesnta!qumix!ittvax!decvax!mulga!munnari!lizs
From: lizs at munnari.OZ (Liz Sonenberg)
Newsgroups: net.lang.f77,net.lang.c
Subject: Re: calling c routines from fortran
Message-ID: <595 at munnari.OZ>
Date: 24 Nov 84 00:09:46 GMT
Date-Received: 25 Nov 84 11:42:35 GMT
References: <100 at athena.UUCP> <1265 at hao.UUCP>
Organization: Comp Sci, Melbourne Uni, Australia
Lines: 48


>    Unfortunately, due to the fact that F77 insists on appending a "_" to all
> of it's routine names, you cannot call *any* C routine from F77 unless it's
> name ends in "_". In addition to that, all F77 arguments are pointers, so you
> can't even call a routine whose name ends in "_" if it is expecting any non-
> pointer arguments (usually the case in C). Therefore, the only way to do this 
> is the following (which is what I gather Liz was suggesting)
>[  details of proposed method comes here ]

  Actually there is a rather horrible kludge for passing an immediate value
(rather than a pointer) directly from an f77 program to a c procedure.
Suppose you want to call the c procedure whose synopsis is

	int z_(intvar)	int intvar;

The following f77 code will pass the value of the integer quantity i to the
procedure  z_  as an immediate value

	   ...
	character*1 x(2)
	   ...
	iretval = z( x( i + 1 - loc(x) )
	   ...

(provided your machine is byte-addressable, and each character occupies a
single byte).  Naturally, you would have to compile the resulting program
without the -C option so that no run-time checking of array subscripts will
be performed.

  Getting access to immediate values that are passed back the other way is a
different story, however, and I know of no convenient way of doing it.

  It is also possible to circumvent the compiler's (very irritating) procedure
of appending underscores to all user-established global variables, provided
the name of the c routine you want to call contains at least two characters.
When calling the routine from your f77 program, give it any convenient name
that contains one less character.  After compiling (but not linking) the f77
progam, the temporary name you have given the routine will appear in the string
table of the object file with an underscore appended.  It is not particularly
difficult to replace this with the true name of the routine you want to call
( I have a rudimentary c program for doing this, if anyone is interested ).
After the modified object file has been linked with the appropriate c files or
libraries, your f77 program will then call the correct routine.

					David Wilson

					{ ...!decvax!munnari!lizs }



More information about the Comp.lang.c mailing list