[comp.lang.c] Fortran vs. C strings

vallury@dartvax.UUCP (RustCat) (06/16/87)

Hello,
	This essentially regards calling a Fortran routine from a C program.
To be more specific, I'm trying to do this on the VMS in order to write a
C interface for the GKS-Plot10 set of Fortran routines.  

	I have no problems with numbers (ints or floats).  This is pretty
straightforward.  The C source simply needs to pass the addresses of the
variables to the Fortran routine and all is fine.  Unfortunately, the
same doesn't seem to work with strings or character variables.  I keep
getting stack dumps irrespective of whether I send the string with single
quotes, or double quotes around it.  

	There was one other way of doing this and it seemed to partially 
work.  That is as follows:

In the C source code, I use the following scheme,

	extern char[30] GKString;
	strcpy (GKString, "...");
	Fortran_Routine ();

And in the corresponding Fortran routine,
	
	COMMON/GKString/MyString
	...

In this case, I don't get the stack dumps, but the string simply doesn't
seem to be getting transmitted to the GKS plotting routine (GTX for example)
properly.  Would this be due to some sort of string terminator syntax
difference between the two languages?  Once again, I've tried enclosing the
string both in single and double quotes but it doesn't work.  

Have any of you come across this problem before?  And managed to get over
it?  This IS on the VMS and I guess the Unix format for external language
addressing might not work.  

I'd appreciate any possible solutions or pointers to tackling these 2 related
problems, namely 1) how to pass string variables directly and 2) the actual
representation of strings (and terminators) between the two languages. 

E-mail would probably be preferable since I don't spend too much time on here
these days.  Thank you.


							Vallury

vallury@dartcms1.BITNET
vallury@dartvax.UUCP

edw@ius2.cs.cmu.edu (Eddie Wyatt) (06/17/87)

   In Fortrash, Integers are actually longs (if you pass pointers to
integers instead of pointers to longs and have it still work, it is because
sizeof(int) == sizeof(long) on the  machine you are working on)

   Fortrash strings (I think) have the format first four(?) bytes
holds the size of the string followed by the characters in the string.

-- 
					Eddie Wyatt

e-mail: edw@ius2.cs.cmu.edu

riddle@woton.UUCP (06/18/87)

In article <1202@ius2.cs.cmu.edu>, edw@ius2.cs.cmu.edu (Eddie Wyatt) writes:
> 
>    Fortrash strings (I think) have the format first four(?) bytes
> holds the size of the string followed by the characters in the string.

This is compiler-dependent.  As I recall, Microsoft Fortran (to name one
example) has two types of character constants, one for use within Fortran and
one for use when interfacing with C.  The former has no accessible length
information or final delimiter stored with it at all, at least not that I
could find; the latter uses a C-style final null as a delimiter.  When you
program in Microsoft Fortran, you indicate that you want a C-style string by
appending a C to it after the final quote (e.g. 'foobar'C).  This is an
awkward solution to the problem, but it works.  Other compilers may not
provide any solution at all. 

--- Prentiss Riddle ("Aprendiz de todo, maestro de nada.")
--- Opinions expressed are not necessarily those of Shriners Burns Institute.
--- riddle@woton.UUCP  {ihnp4,harvard,seismo}!ut-sally!im4u!woton!riddle

stevesu@copper.UUCP (06/19/87)

I was going to reply by mail as requested, but since
misinformation has already been posted, I'll present a
quick synopsis here.

VMS, in spite of its faults, embodies a nice concept called the
VAX Calling Standard, which virtually guarantees that programs
written in any language can call each other fairly easily.
The calling standard describes not only the stack frame (which is
implemented by the VAX CALLS and CALLG instructions), but also
conventions for passing typed data, which is the responsibility
of the various compilers (or, in the case of a low-level high
level language like C, the programmer).

Character strings are passed by descriptor.  A descriptor is an
8-byte structure that looks like this:
	 _______________________________
	|__c_l_a_s_s__|__d_t_y_p_e__|_____l_e_n_g_t_h_____|
	|______________p_o_i_n_t_e_r___________|

or, as a C struct:

	struct descriptor
		{
		unsigned short int dsc_length;
		unsigned char dsc_dtype;
		unsigned char dsc_class;
		char *dsc_pointer;
		};

When passing a string to another routine, it is usually
sufficient to fill in the dtype and class as 0.  (Purists may
wish to use more appropriate values; see references below.)

Here is a quick example.  SYS$ASSIGN is not written in Fortran,
but the descriptor-passing mechanism is the same.

	#define IO$_WRITEVBLK 0x30

	main()
	{
	struct descriptor d;
	short int channel;

	d.dsc_pointer = "sys$output";
	d.dsc_length = 10;
	d.dsc_dtype = d.dsc_class = 0;

	sys$assign(&d, &channel, 0, 0);
	sys$qiow(0, channel, IO$_WRITEVBLK, 0, 0, 0, "Hello, world!\r", 14,
								0, 0, 0, 0);
	}

Note that descriptors are almost always passed by reference
(struct descriptor *).

Passing a descriptor which is to be filled in by the caller, and
accepting a descriptor that has been passed by another routine,
are trickier because you have to deal with some more unusual
descriptor classes, including one in which the string is stored
two bytes beyond the pointer, the pointer pointing to a word
holding the string's current length.  I believe that
LIB$ANALYZE_SDESC can be used to deal with arbitrary string
descriptors in a general way, without having to know about all of
the descriptor classes.

There are some header files or something that come with VAXC,
DEC's VMS C compiler, that make handling descriptors a bit
easier.

                                           Steve Summit
                                           stevesu@copper.tek.com

References:

	VAX-11 Guide to Creating Modular Library Procedures
		(Obsolete VMS V3 manual), section 4.5
	VAX/VMS Run-Time Library Routines Reference Manual,
		section 2.6
	Introduction to VAX/VMS System Routines, section 2.9.1

Disclaimer: This entire article has of course been concerned
solely with VMS-related issues.  Strings are passed to and from
Fortran programs on Unix in a completely different way.

drw@cullvax.UUCP (Dale Worley) (06/19/87)

edw@ius2.cs.cmu.edu (Eddie Wyatt) writes:
>    In Fortrash, Integers are actually longs (if you pass pointers to
> integers instead of pointers to longs and have it still work, it is because
> sizeof(int) == sizeof(long) on the  machine you are working on)

I'm somewhat bothered that none of you are specifying which
implementations of the two languages you are discussing.  When you want
to interface two different language systems, you have to figure out
how both of them map the language structures to machine code, and
figure out the right hacks to get the information across.  In any
case, the particular solution will only be good for the two language
implementations involved.

Dale
-- 
Dale Worley	Cullinet Software		ARPA: cullvax!drw@eddie.mit.edu
UUCP: ...!seismo!harvard!mit-eddie!cullvax!drw
If you light a match, how much mass does it convert into energy?

edw@ius2.cs.cmu.edu (Eddie Wyatt) (06/20/87)

In article <1299@cullvax.UUCP>, drw@cullvax.UUCP (Dale Worley) writes:
> edw@ius2.cs.cmu.edu (Eddie Wyatt) writes:
> >    In Fortrash, Integers are actually longs (if you pass pointers to
> > integers instead of pointers to longs and have it still work, it is because
> > sizeof(int) == sizeof(long) on the  machine you are working on)
> 
> I'm somewhat bothered that none of you are specifying which
> implementations of the two languages you are discussing.  When you want
> to interface two different language systems, you have to figure out
> how both of them map the language structures to machine code, and
> figure out the right hacks to get the information across.  In any
> case, the particular solution will only be good for the two language
> implementations involved.
> 
> Dale
> -- 
> Dale Worley	Cullinet Software		ARPA: cullvax!drw@eddie.mit.edu
> UUCP: ...!seismo!harvard!mit-eddie!cullvax!drw
> If you light a match, how much mass does it convert into energy?

   F77 on Berkley Unix OS.  Its been a while since I've played with 
stuff like that.  Some vendor's language manual with have the details
of implementation.

-- 
					Eddie Wyatt

e-mail: edw@ius2.cs.cmu.edu

terrorist, cryptography, DES, drugs, cipher, secret, decode, NSA, CIA, NRO.

henry@utzoo.UUCP (Henry Spencer) (06/21/87)

> VMS, in spite of its faults, embodies a nice concept called the
> VAX Calling Standard, which virtually guarantees that programs
> written in any language can call each other fairly easily.
> The calling standard describes not only the stack frame (which is
> implemented by the VAX CALLS and CALLG instructions), but also
> conventions for passing typed data...

It is worth mentioning another aspect of the VAX Calling Standard:  it is
Ghodawful slow.  The all-singing-all-dancing CALLS and CALLG are often
slower than "rolling your own" using more primitive instructions.  (I am
told that the insides of VMS do this quite extensively.)  C function calls
using CALLS on the VAX 780 are slower than C function calls on the 11/70,
which is a bit embarrassing considering relative ages, technologies, and
data-path widths (not to mention prices).
-- 
"There is only one spacefaring        Henry Spencer @ U of Toronto Zoology
nation on Earth today, comrade."   {allegra,ihnp4,decvax,pyramid}!utzoo!henry

peter@sugar.UUCP (Peter DaSilva) (06/26/87)

>    Fortrash strings (I think) have the format first four(?) bytes
> holds the size of the string followed by the characters in the string.

That is implementation dependent. They may also do such things as store
a byte length at the address, or even store a value *before* the address
passed. They may not even have a length you can use at all, if it's an
old Fortran. I would suggest you do this:

char foo[80];

main()
{
	int i;

	fortest();

	for(i = 0; i < 80; i++)
		printf("%03o", foo[i]);
}

       SUBROUTINE FORTEST
       CHARACTER*80 BAR
       COMMON /FOO/ BAR
       BAR = 'TEST STRING'
       END

Then get your ascii table and examine the output.

ark@alice.UUCP (07/01/87)

In article <223@sugar.UUCP>, peter@sugar.UUCP writes:
> That is implementation dependent. They may also do such things as store
> a byte length at the address, or even store a value *before* the address
> passed. They may not even have a length you can use at all, if it's an
> old Fortran.

It is difficult and unnecessary for a Fortran 77 compiler that conforms
to the ANSI standard to store a length with a character string.

It is unnecessary because the length of every string is known to
the compiler as a constant, except for parameters.  Parameters must
be handled specially anyway, because they can be temporaries.

It is difficult because the language defines the meaning of things like:

	CHARACTER A*10, B*10, C*20
	COMMON A, B
	EQUIVALENCE (A, C)

so that the first 10 characters of C are equivalent to the 10 characters
of A and the next 10 characters of C are equivalent to the 10 characters
of B.  It's hard to do this and still store a count.