[net.unix] C calls FORTRAN subroutine

leung@imsvax.UUCP (Aldrin Leung) (10/12/84)

I have difficulty to use a C main program to call a Fortran
subroutine that have I/O and would like anybody have
related experience to give me some help.  I usually don't
read mail under unix.wizard.  Please send mail to me.  The
following is what I did.

In the C program, I have
----------
#include <stdio.h>

main()
{
try_()
}
----------

In the Fortran program, I have
----------
      subroutine try
      write (6,100)
100   format ("subprogram")
      end
----------

I use "cc -c main.c", "f77 -c try.f", and
"cc main.o try.o -lF77 -lU77 -lI77"

No output like "subprogram" is printed.

Thanks in advance!

Aldrin Leung
...umcp-cs!eneevax!imsvax!leung  or
...umcp-cs!cvl!elsie!leung

woods@hao.UUCP (Greg "Bucket" Woods) (10/13/84)

> In the C program, I have
> ----------
> #include <stdio.h>
> 
> main()
> {
> try_()
> }
> ----------
> 
> In the Fortran program, I have
> ----------
>       subroutine try
>       write (6,100)
> 100   format ("subprogram")
>       end
> ----------
> 

  This is a weird one. I know why it doesn't work, but knowing why isn't much
help. I put an "fflush(stdout)" call in the main program after the call to
"try", and then ran "adb" on this program, putting a breakpoint in "write".
The result of that shows that it is trying to write the string "subprogram"
on file descriptor 3. How about it, compiler wizards? What the '&"#%@*! is
going on?

--Greg
-- 
{ucbvax!hplabs | allegra!nbires | decvax!stcvax | harpo!seismo | ihnp4!stcvax}
       		        !hao!woods
   
     "...the bus came by, and I got on, that's when it all began..."

donn@utah-gr.UUCP (Donn Seeley) (10/13/84)

From the original article by Aldrin Leung:

	In the C program, I have
	----------
	#include <stdio.h>
	
	main()
	{
	try_()
	}
	----------
	
	In the Fortran program, I have
	----------
	      subroutine try
	      write (6,100)
	100   format ("subprogram")
	      end
	----------

When these routines are compiled, loaded together and run, they print
nothing.

The problem here is that f77's I/O system needs to be 'primed'.  The
standard f77 main() routine does this for you, but if you substitute
your own C main() routine then you have to do the 'priming' yourself.
There is an f77 I/O clean-up routine which you can call too (it's
not as important, though).  Without the 'priming', f77 I/O (at least
on pre-defined units) will have no effect.  A demonstration of the
the use of the priming and clean-up routines appears below.

Since f77 uses the C stdio library, you can mix C and f77 I/O by using
stdio in your C routines rather than straight Unix system calls.  Since
it may be difficult to predict which stdio file pointers are associated
with which f77 unit numbers, it's probably a good idea to stick with
'stdin', 'stdout' and 'stderr' when doing C I/O.

One other thing that is useful to have is a MAIN_() routine.  This is
normally created by f77 when it compiles the MAIN section of a program,
but if you replace the f77 main() with a C main(), it never gets
defined and f77 will complain about it if you use f77 to compile or
load your program.  (Yes, f77 will compile C files, one of its many
peculiar features.  Yes, this is useful because it means you can get
all of the f77 libraries without having to specify them explicitly, as
you would if you loaded your C and f77 objects 'by hand'.  Again, see
below for an example of this.)

Here's an example that demonstrates all of these features.  Put the
following code in a file 'c_main.c':

------------------------------------------------------------------------
# include	<stdio.h>

main( argc, argv, envp )
	int		argc;
	char		**argv;
	char		**envp;
{
	/*
	 * Process your arguments and environment here.
	 */

	/*
	 * Prime the f77 I/O routines, call MAIN_(), and clean up.
	 */
	f_init();
	MAIN_();
	f_exit();
	exit( 0 );
}

MAIN_()
{
	/*
	 * Call various f77 and C routines.
	 */
	c_routine();
	f77routine_();
}

c_routine()
{
	printf( "First some C I/O, then" );
}
------------------------------------------------------------------------

Put the following code in a file named 'f77_routines.f':

------------------------------------------------------------------------
	subroutine f77routine()

	print *, 'some f77 I/O.'

	return
	end
------------------------------------------------------------------------

Then compile the two files like this:

------------------------------------------------------------------------
% f77 c_main.c f77_routines.f -o cf
c_main.c:
f77_routines.f:
   f77routine:
%
------------------------------------------------------------------------

When you run the program, you get:

------------------------------------------------------------------------
% ./cf
First some C I/O, then  some f77 I/O.
%
------------------------------------------------------------------------

I hope this wasn't too complicated,

Donn Seeley    UCSD Chemistry Dept.       ucbvax!sdcsvax!sdchema!donn
32 52' 30"N 117 14' 25"W  (619) 452-4016  sdcsvax!sdchema!donn@nosc.ARPA

chris@umcp-cs.UUCP (Chris Torek) (10/13/84)

Doesn't the 4.2BSD f77 I/O library require a call to ``ioinit'' first?
-- 
(This mind accidently left blank.)

In-Real-Life: Chris Torek, Univ of MD Comp Sci (301) 454-7690
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

mather@uicsl.UUCP (10/15/84)

I tried this little teaser of a program and nothing appears on
stdout, however, a little file called fort.6 is generated with the
contents:     subprogram
inside.

Some not-too-well-known info:

1) opening a file with "open(unit=n)" creates a file "fort.n"
	unless ioinit has been used to change the default. ioinit(3F)
	claims that there is no automatic filename association for
	fortran logical units, but there is. In libI77, see err.c.

2) It is difficult to pass C file descriptors to f77 as unit #s
	and visa versa.

3) Opening a file as "open(unit=n,file='/dev/tty')"  will put all output
	written on unit n to your tty. Impossible to separate standard
	output and standard error, however. I placed this open statement
	prior to the write and it worked, but this isn't good if you call
	this routine more than once, since it isn't nice to reopen a file
	if it is already open. It should be closed first. But closing,
	then opening puts the pointer at the beginning of the file (unless
	ioinit is used to make files appendable).


Callling C from FORTRAN is nice, but going the other way is a real pain,
especially since you have to include all of the libF77 and libI77 junk.
Messy messy messy.

					b.c.mather
					software surgeon
					uiucdcs!uicsl!mather

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (10/16/84)

Exactly.  The Fortran I/O system requires initialization, and a C main
program will not do it by default.

root@uokmet.UUCP (10/22/84)

/***** uokmet:net.unix / uicsl!mather /  4:31 pm  Oct 14, 1984 */

>>> Calling C from FORTRAN is nice, but going the other way is a real pain,
>>> especially since you have to include all of the libF77 and libI77 junk.
>>> Messy messy messy.

There is a nice little trick that I've discovered of recent.  If you
have a C main program that calls FORTRAN routines, use "MAIN__()"
instead of "main()", then compile with f77!  The linking is done for you.

There is documentation called "A Portable Fortran 77 Compiler"
(found in "UNIX Programmers' Manual" Volume 2B, at least that's
its location for 2BSD) that might also be of some use.

	Kevin W. Thomas
	Univ. of Oklahoma
	Norman, OK  73019

UUCP:  ...!ctvax!uokvax!uokmet!kwthomas

leiby@masscomp.UUCP (10/22/84)

Regarding the fellow who calls a FORTRAN subroutine from his C
program and is then unable to do I/O from within the FORTRAN
subroutine:

The problem here is that the FORTRAN start-up code maps logical
unit numbers to Unix(tm) file descriptors in an implementation
dependent way.  Since the main program is in C, none of this
setup gets done.  Thus when the FORTRAN I/O library call is
executed, it can't find a valid logical unit number table,
and the output (if any) is trashed.  I'd be amazed if the fellow
gets any output at all.

A solution?  Unless you have the compiler code to look at, I'm
afraid it's like the old joke:

	Patient:  Dr., it hurts when I do this.
	Doctor:	  Well, don't do that!!!

		Mike Leibensperger
		{decvax,ihnp4,harpo,tektronix}!masscomp!leiby
-- 
Mike Leibensperger
{decvax,tektronix,harpo}!masscomp!leiby
Masscomp; One Technology Park; Westford MA 01886

joels@tektronix.UUCP (Joel Swank) (10/31/84)

> Regarding the fellow who calls a FORTRAN subroutine from his C
> program and is then unable to do I/O from within the FORTRAN
> subroutine:
> 
> The problem here is that the FORTRAN start-up code maps logical
> unit numbers to Unix(tm) file descriptors in an implementation
> dependent way.  Since the main program is in C, none of this
> setup gets done.  Thus when the FORTRAN I/O library call is
> executed, it can't find a valid logical unit number table,
> and the output (if any) is trashed.  I'd be amazed if the fellow
> gets any output at all.
> 
> A solution?  Unless you have the compiler code to look at, I'm
> afraid it's like the old joke:
> 
I had this problem under 4.2bsd and I found that output was going to
a file called fort.6. I circumvented the problem using a symbolic
link:
      ln -s /dev/tty fort.6

Just execute this command before running the program, and output will
go to the terminal.

Joel Swank
Software Center Tools Support
50-487
Tektronix
Beaverton OR 97077
(503) 627-4403