[comp.lang.c] passing Fortran characters to C

staff@cadlab.sublink.ORG (Alex Martelli) (02/08/91)

springer@khonshu.Colorado.EDU (Jann Springer) writes:
    ...
:To transfer a character string between C and Fortran involves
:using a descriptor, which is how Fortran passes character strings.
    (explanation deleted)
:This explanation assumes you are using VMS and not Ultrix.

Here's a technique which works on VMS, Ultrix, several more Unixen, and
ALMOST on OS/2 and MSDOS (with some extra complications, omitted).
We have a header file, ftnintf.h, which has (simplified):

#if (identification of your choice for most f77-derived Fortran's)
#   define __NEED_UNDERLINE     1
#endif
/* no underline for VMS, HP/UX, IBM RISC/6000, etc */

#if __NEED_UNDERLINE
#   define FTN(x)       _paste(x,_)
#else
#   define FTN(x)       x
#endif

typedef short I2; typedef long I4; typedef char *PTR;

#if  VMSVAX
typedef struct { I2 len; I2 dum; PTR adr; }  VAXCH;
#   define DCA(x)       x
#   define DCL(x)
#   define DCHAL(x)     VAXCH*x
#   define CHA(x)       (x->adr)
#   define LEN(x)       ((I4)(x->len))
#else
#   if  HP800
#       define DCA(x)   x, _paste(L,x)
#       define DCL(x)
#   else
#       define DCA(x)   x
#       define DCL(x)   ,_paste(L,x)
#   endif  /* HP800 */
#   ifdef APO
#       define DCHAL(x)     PTR x;I2* _paste(L,x)
#       define LEN(x)       ((I4)*_paste(L,x)
#   else
#       define DCHAL(x)     PTR x;I4 _paste(L,x)
#       define LEN(x)       _paste(L,x)
#   endif  /* APO */
#   define CHA(x)           x
#endif

where APO identifies Apollo Domain/OS machines, HP800 is for HP
9000/800, VMSVAX for guess-what.  _paste(a,b) is a macro to give ONE
token out of the two tokens a and b; this is obtained with a##b in ANSI
C, with a/**/b in common or garden C.  There are further complications
for access to COMMON blocks, Microsoft compilers, procedures passed as
parameters, calling back from Fortran to C, and so on, but I'm going to
spare you these.  Anyway the usage is then, say:

#include "ftnintf.h"
void
FTN(counteqs)(DCA(one), DCA(two), ires DCL(one) DCL(two))
    DCHAL(one); DCHAL(two); I2 *ires;
{
    register int i, j;
    for(i=j=0; i<LEN(one) && i<LEN(two); i++)
        if(CHA(one)[i]==CHA(two)[i]) j++;
    *ires = j;
}

which is now the same thing as:

     SUBROUTINE COUNTEQS(CHONE, CHTWO, IRES)
     CHARACTER*(*) CHONE, CHTWO
     INTEGER*2 IRES
     INTEGER I,J
     I=1
     J=0
100  IF(I.gt.LEN(CHONE).or.I.gt.LEN(CHTWO)) GOTO 900
     IF(CHONE(I:I).eq.CHTWO(I:I)) J=J+1
     I=I+1
     GOTO 100
900  IRES=J
     RETURN
     END

on all machines.  Yes I know, the C-side syntax ain't exactly pretty,
but it's the only way we've found to keep C code interfacing to Fortran
bit-for-bit the same on all platforms we support, a task which had been
diagnosed as "absolutely impossible" by more than one "expert":-).

I would appreciate further discussion on this, but NO e-mail please -
we PAY for mail we get, and it's already costing me a pretty penny to
donate this to the fortran-cum-c community on the net!-).
-- 
Alex Martelli - CAD.LAB s.p.a., v. Stalingrado 53, Bologna, Italia
Email: (work:) staff@cadlab.sublink.org, (home:) alex@am.sublink.org
Phone: (work:) ++39 (51) 371099, (home:) ++39 (51) 250434; 
Fax: ++39 (51) 366964 (work only), Fidonet: 332/401.3 (home only).