lizh@athena.UUCP (Liz Heller) (12/17/84)
*** 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@hao.UUCP (Greg "Bucket" Woods) Newsgroups: net.lang.f77,net.lang.c Subject: Re: calling c routines from fortran Message-ID: <1265@hao.UUCP> Date: 19 Nov 84 18:24:18 GMT Date-Received: 22 Nov 84 15:05:11 GMT References: <100@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@brl-tgr.ARPA (Doug Gwyn <gwyn>) Newsgroups: net.lang.f77,net.lang.c Subject: Re: calling c routines from fortran Message-ID: <5943@brl-tgr.ARPA> Date: 20 Nov 84 17:33:50 GMT Date-Received: 24 Nov 84 07:08:19 GMT References: <100@athena.UUCP> <1265@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@munnari.OZ (Liz Sonenberg) Newsgroups: net.lang.f77,net.lang.c Subject: Re: calling c routines from fortran Message-ID: <595@munnari.OZ> Date: 24 Nov 84 00:09:46 GMT Date-Received: 25 Nov 84 11:42:35 GMT References: <100@athena.UUCP> <1265@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 }