Path: utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!thunder.mcrcim.mcgill.edu!snorkelwacker.mit.edu!usc!zaphod.mps.ohio-state.edu!pacific.mps.ohio-state.edu!linac!midway!gargoyle!igloo!ddsw1!proxima!undeed!barrett From: barrett@Daisy.EE.UND.AC.ZA (Alan P. Barrett) Newsgroups: comp.lang.c Subject: Re: mixing fortran and c Message-ID: <1991Feb18.110728.10273@Daisy.EE.UND.AC.ZA> Date: 18 Feb 91 11:07:28 GMT References: <160@mailgzrz.tu-berlin.de> <2952@charon.cwi.nl> Organization: Univ. Natal, Durban, S. Africa Lines: 289 In article <2952@charon.cwi.nl>, dik@cwi.nl (Dik T. Winter) writes: > In article <160@mailgzrz.tu-berlin.de> > duns1222@w203zrz.zrz.tu-berlin.de (Martin Dunschen) writes: > > Hi all you high experienced C/FORTRAN programmers ! > [...] > > But the last remaining thing is: > > HOW TO PASS STRINGS ? > > > The answer can range from simple to impossible. Here are the four methods I have seen: a) A string passed from a Fortran routine to a C routine appears to the C routine as if it were a struct. This struct contains the string length and a pointer to the actual characters, and possibly some other stuff as well. b) Like (a), but a pointer to the struct is passed. c) A string passed from a Fortran routine to a C routine appears to the C routine as if it were two consecutive arguments: a pointer to the data followed by an integer length. (This might actually be indistinguishable from method (a) on some systems.) d) Like (c), but all the Fortran string length arguments are collected at the end of the argument list, after all the other arguments. To clarify what I mean, here is an example. If you have a Fortran routine that wants to call a subroutine declared like this: SUBROUTINE SUBR (I, C1, J, C2) INTEGER I, J CHARACTER *(*) C1, C2 then the subroutine can possibly be replaced by a C routine like one of these: /* method (a) */ void subr (int i, struct ftnstring c1, int j, struct ftnstring c2); /* method (b) */ void subr (int i, struct ftnstring *c1, int j, struct ftnstring *c2); /* method (c) */ void subr (int i, char* c1data, int c1length, int j, char* c2data, int c2length); /* method (d) */ void subr (int i, char* c1data, int j, char* c2data, int c1length, int c2length); I am appending some sample code that I have used to convert between C and Fortran strings. ftntypes.h declares how the Fortran system represents strings. Find out how your system does it, and edit this file appropriately. ftnstring.c contains the fstringtoc() and cstringtof() functions, which do low level conversion between the two string types, truncating or blank-padding as necessary. These are intended to be called from a C routine which is in turn called from Fortran. ftngetterm.c contains a Fortran-callable function to get the name of the terminal from which the program was invoked. --apb Alan Barrett, Dept. of Electronic Eng., Univ. of Natal, Durban, South Africa Internet: barrett@ee.und.ac.za (or %ee.und.ac.za@saqqara.cis.ohio-state.edu) UUCP: m2xenix!quagga!undeed!barrett PSI-Mail: PSI%(6550)13601353::BARRETT # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by Alan P Barrett on Mon Feb 18 12:48:09 1991 # # This archive contains: # ftntypes.h ftnstring.c ftngetterm.c # LANG=""; export LANG PATH=/bin:/usr/bin:$PATH; export PATH echo x - ftntypes.h cat >ftntypes.h <<'@EOF' /* @(#)ftntypes.h 1.5 90/02/01 */ /* ftntypes.h * A.P. Barrett * defines types for C/Fortran interface */ /********* FORTRAN character variables ********/ /* Define preprocessor symbol F_CHR_STRUCT or F_CHR_STRUCTP if Fortran passes * each character arg as an item of type "ftn_character". Use F_CHR_STRUCT * if this item is in fact a structure, or F_CHR_STRUCTP if the item is * a pointer to a structure. * * Define F_CHR_LENARG or F_CHR_LENARG_END if Fortran passes two arguments, * a char pointer and an integer length, for each character string. Use * F_CHR_LENARG if the lengths are intermixed with the string pointers, or * F_CHR_LENARG_END if all the lengths are grouped together at the end of the * argument list. */ #if defined(hp9000s300) # define F_CHR_LENARG_END #endif #if defined(hp9000s500) # define F_CHR_STRUCT #endif #if defined(hp9000s800) # define F_CHR_LENARG /* could use F_CHR_STRUCT instead ??? */ #endif /* If Fortran passes a structure (or pointer to a structure) define it here. * Structure members length and start must be the length and address of the * string. */ #if defined(F_CHR_STRUCT) || defined(F_CHR_STRUCTP) typedef struct { # if defined(hp9000s500) long junk1,junk2,junk3; /* I don't know what this is */ long length; /* length of string */ char *start; /* pointer to start of actual data */ # endif # if defined(hp9000s800) int length; /* length of string */ char *start; /* pointer to start of actual data */ # endif } # if defined(F_CHR_STRUCT) ftn_character; # else /* F_CHR_STRUCTP */ * ftn_character; # endif #endif /********** FORTRAN logical variables *************/ typedef long ftn_logical; #define ftn_TRUE ((ftn_logical)~0) /* any non-zero value will do */ #define ftn_FALSE ((ftn_logical)0) /********** FORTRAN integer, real, doubleprecision, complex *************/ typedef long ftn_integer; typedef float ftn_real; typedef double ftn_doubleprecision; typedef struct { ftn_real re,im; /* real and imaginary parts */ } ftn_complex; @EOF chmod 444 ftntypes.h echo x - ftnstring.c cat >ftnstring.c <<'@EOF' /* ftnstring.c * A P Barrett, 1986 * conversions between fortran and C strings * * fstringtoc (fstring_start, fstring_length, cstring, cstring_length) * converts a Fortran string to a C string, and returns a pointer to the * C string. The C string is truncated if fstring_length is larger then * cstring_length-1. * * cstringtof (cstring, fstring_start, fstring_length) * converts a C string to a Fortran string, and returns the length of the * Fortran string, excluding additional trailing blanks. The Fortran * string is truncated or blank filled as appropriate. */ char *fstringtoc (fstring_start, fstring_length, cstring, cstring_length) char *fstring_start; int fstring_length; char *cstring; int cstring_length; { int i; /* first copy the contents of the fortran string */ for ( i=0 ; iftngetterm.c <<'@EOF' /* ftngetterm.c * A P Barrett, 1987 * return term name to a fortran prog */ #include "ftntypes.h" int cstringtof(); /* convert char array to fortran string */ char *ttyname(); /* get terminal name */ int isatty(); /* this function returns the terminal name in a fortran * character variable. * call from fortran: * character*(*) termname * integer length * length = gettermname (termname) */ #ifdef F_CHR_STRUCT int gettermname (termname) ftn_character termname; # define termname_start termname.start # define termname_length termname.length #endif #ifdef F_CHR_STRUCTP int gettermname (termname) ftn_character termname; # define termname_start termname->start # define termname_length termname->length #endif #ifdef F_CHR_LENARG int gettermname (termname_start,termname_length) char *termname_start; int termname_length; #endif #ifdef F_CHR_LENARG_END int gettermname (termname_start,termname_length) char *termname_start; int termname_length; #endif { int length; char *name; int num; /* if any of stderr, stdin or stdout is a terminal, get its name */ if (isatty(num=2) || isatty(num=0) || isatty(num=1)) { name = ttyname(num); } else { name = "??"; } length = cstringtof ( name, termname_start, termname_length ); return (length); } @EOF chmod 444 ftngetterm.c exit 0