(Dr.R.K.) Fortran & C - Mixing Fortran & C

Go to Top Go to Bottom blank blank Go up one level R.K.'s Home Page Keyword Index Site Map Help Linux
The following are examples that demonstrate how to call Fortran from C or vice versa. This has also been worked into individual slides (or a collected version).

Fortran & C differences

  • Fortran :
    • Passes by address
    • Routine names are case insensitive
    • Arrays are column-major
    • Strings contain length
  • C :
    • Passes by value
    • Names are case sensitive
    • Arrays are row-major
    • "Strings" are null terminated

These demo codes use the Cray C predefined macro _CRAY to conditionally compile any Cray dependent parts, _AIX for any IBM xlc dependent parts, and __hpux for HP machines. Most everything else are satisfied by the defaults.

Note that for the Cray that the C parts need to convert Fortran character strings to C char pointers. On workstations this is usually no problem. In addition, since Fortran is case insensitive Cray Fortran defaults subroutine names to UPPERCASE. Workstations default to lowercase with an underscore (_) usually appended to the name.

Cray Fortran & C data types:

Fortran C size(bits)
INTEGER int 46/64
cft77 -i64 cc -nofastmd  
INTEGER long 64
REAL double or float 64
DOUBLE PRECISION long double 128
COMPLEX float complex
or double complex
128
SUBROUTINE SUBR( ) void SUBR( )  
FUNCTION FN( ) double FN( )  
COMMON /CB/data(10) struct common {
double data[10];
} CB;
 

The demo codes use the IBM C predefined macro _AIX to conditionally compile any IBM dependent parts.

In addition, since Fortran is case insensitive IBM Fortran defaults subroutine names to lowercase and does not append or prepend an underscore (_) to the name.

IBM Fortran & C data types:

Fortran C size(bits)
INTEGER*1 signed char 8
INTEGER*2 short 16
INTEGER int 32
REAL float 32
DOUBLE PRECISION double 64
COMPLEX 2 float struct 64
DOUBLE COMPLEX 2 double struct 128
SUBROUTINE SUBR( ) void subr( )  
FUNCTION FN( ) float fn( )  
COMMON /CB/data(10) ?  

f2c.f calls f2cfn.c


      PROGRAM F2C
C
      CHARACTER*32 NAME
      INTEGER AGE
      REAL TEMP
C
      NAME = "Knut"
C add null character at end for portable & safe handling by C
      NAME(LEN(NAME):LEN(NAME)) = CHAR(0)
C note that LEN(NAME) = 32 in this case
      AGE = 4
      TEMP = 98.6
      CALL NAMEAGE(NAME, AGE, TEMP)
      END

f2cfn.c called by f2c.f


 
#include <string.h>
#ifdef _CRAY
#  include <fortran.h>
#  define nameage       NAMEAGE
#else
#  if !defined(_AIX) && !defined(__hpux)
#    define nameage     nameage_
#  endif
#  define _fcd          char *
#  define _fcdtocp(a)   (a)
#  define _fcdlen(a)    strlen(a)
#endif

void nameage(_fcd name, int *age, float *temp) {
        char *cp;
        size_t len;

        cp = _fcdtocp(name);    /* convert to C char* */
        len = _fcdlen(name);

        /* strip trailing blanks */
        while (cp[len-1] == ' ' || cp[len-1] == '\0') --len;
        printf("Hello %.*s, who is %d years old, "
                "has a temperature of %4.1f\n", len, cp, *age, *temp);
}
 

Compilation Steps for the Above Example

  • Cray - PVPs - UNICOS
    • cc -c f2cfn.c
    • cf77 f2c.f f2cfn.o
    • (or substitute f90 for cf77)
  • IBM - SP2 - AIX
    • xlc -c f2cfn.c
    • xlf f2c.f f2cfn.o
  • SGI - IRIX
    • gcc -c f2cfn.c
    • f77 f2c.f f2cfn.o
  • SUN - SunOS
    • gcc -c f2cfn.c
    • f77 f2c.f f2cfn.o
  • HP - UX
    • gcc -c f2cfn.c
    • f77 f2c.f f2cfn.o
  • PC - Linux
    • gcc -c f2cfn.c
    • g77 f2c.f f2cfn.o

Output for the Above Example

Hello Knut, who is 4 years old, has a temperature of 98.6

c2f.c calls c2ffn.f


 
#include <string.h>
#ifdef _CRAY
#  include <fortran.h>
#  define nameage      NAMEAGE
#else
#  if !defined(_AIX) && !defined(__hpux)
#    define nameage    nameage_
#  endif
#  define _fcd          char *
#  define _cptofcd(a,b) (a)
#  define _fcdlen(a)    strlen(a)
#endif

void nameage(_fcd name, int *nlen, int *age, float *temp);

int main() {
        char *name = "Knut";
        _fcd fp;
        int nlen,age = 4;
        float temp = 98.6;

        nlen = strlen(name);
        fp = _cptofcd(name, nlen);      /* convert to Fortran string */

        nameage(fp, &nlen, &age, &temp);
        return 0;
}

c2ffn.f called by c2f.c


      SUBROUTINE NAMEAGE(NAME, NLEN, AGE, TEMP)
      CHARACTER*(*) NAME
      INTEGER NLEN,AGE
      REAL TEMP
C
      WRITE(6,1000) NAME(1:NLEN),AGE,TEMP
 1000 FORMAT(1X,'Hello ',A,', who is ',I2,
     .       ' years old, has a temperature of ', f4.1)
      RETURN
      END

Compilation Steps for the Above Example

To discover which libraries are necessary for Fortran modules, compile a short Fortran test program and add the -V or -v option (or whatever) to get a verbose execution listing to show what arguments are being passed to each compilation stage.
  • Cray - PVPs - UNICOS
    • cf77 -c c2ffn.f
    • cc -c c2f.c
    • cf77 c2f.o c2ffn.o
    • (or substitute f90 for cf77)
  • IBM - SP2 - AIX
    • xlf -c c2ffn.f
    • cc c2f.c c2ffn.o -lxlf90 -lxlf -lm
  • SGI - IRIX
    • f77 -c c2ffn.f
    • gcc c2f.c c2ffn.o -lF77 -lm -lU77 -lI77 -lisam -lmpc -lc
  • SUN - SunOS
    • f77 -c c2ffn.f
    • gcc c2f.c c2ffn.o -L/usr/lang/SC0.0 -lF77 -lm -lc
  • HP - UX
    • f77 -c c2ffn.f
    • gcc c2f.c c2ffn.o -lcl -lisamstub -lc
  • PC - Linux
    • g77 -c c2ffn.f
    • gcc -c c2f.c
    • g77 c2f.o c2ffn.o

Output for the Above Example

 Hello Knut, who is  4 years old, has a temperature of 98.6

Brought to you by: R.K. Owen,Ph.D.
This page is http://rkowen.owentrek.com/howto/FandC/FandC.call.html