Interfacing with C

Absoft Fortran 77 and 90 are designed to be fully compatible with the Absoft C/C++ and the Microsoft C/C++ compilers. The linker can be used to freely link C modules with Fortran main programs and vice versa. However, some precautions must be taken to ensure proper interfacing. Data types in arguments and results must be equivalent and some changes to the linking procedure must be made. All of these rules are detailed below. Be sure to follow them closely, or the results will be both unpredictable and invalid.

FORTRAN Data Types in C
Declarations for FORTRAN data types and the equivalent declarations in C are as follows:

  FORTRAN              C
LOGICAL*1 l     unsigned char l;
LOGICAL*2 m     unsigned short m;
LOGICAL*4 n     unsigned long n;

CHARACTER*n c   char c[n];

INTEGER*1 i     char i;
INTEGER*2 j     short j;
INTEGER*4 k     int k;
                long k;

REAL*4 a        float a;
REAL*8 d        double d;

COMPLEX*8 c     struct complx {
                     float x;
                     float y;
                };
                struct complx c;

COMPLEX*16 d    struct dcomp {
                     double x;
                     double y;
                };
                struct dcomp d;

RECORD ...      struct ...


The storage allocated by the C language declarations will be identical to the storage allocated by the corresponding FORTRAN declaration. There are additional cautions when passing FORTRAN strings to C routines. See Passing Strings to C later in this chapter for more information.

Passing arguments Between C and FORTRAN
The Absoft FORTRAN 77 compiler uses the calling conventions of the C language. Therefore, a FORTRAN routine may be called from C without being declared in the C program and vice versa, if the routine returns all results in parameters. Otherwise, the function must be typed compatibly in both program units. In addition, care must be taken to pass compatible parameter types between the languages. Refer to the table in the previous section.

Reference Parameters
By default, all FORTRAN arguments to routines are passed by reference, which means pointers to the data are passed, not the actual data. Therefore, when calling a FORTRAN procedure from C, pointers to arguments must be passed rather than values. Both integer and floating point values may be passed by reference. Consider the following example:

SUBROUTINE sub(a_dummy,i_dummy)
REAL*4 a_dummy
INTEGER*4 i_dummy

WRITE (*,*) 'The arguments are ',a_dummy, ' and ',i_dummy
RETURN
END


The above subroutine is called from FORTRAN using the call statement:

a_actual = 3.3
i_actual = 9
CALL sub(a_actual, i_actual)
END


However, to call the subroutine from C, the function reference must explicitly pass pointers to the actual parameters as follows:

main()
{
float a_actual;
int i_actual;

      a_actual = 3.3;
      i_actual = 9;
      sub(&a_actual,&i_actual);
}


Note: The values of the actual parameters may then be changed in the FORTRAN subroutine with an assignment statement or an I/O statement.

When calling a C function from FORTRAN with a reference parameter, the C parameters are declared as pointers to the data type and the FORTRAN parameters are passed normally:

PROGRAM convert_to_radians
WRITE (*,*) 'Enter degrees:'
READ (*,*) c
CALL c_rad (c)
WRITE (*,*) 'Equal to ',c,' radians'
END



void c_rad(c)
float *c;
{
      float deg_to_rad = 3.14159/180.0;
      *c = *c * deg_to_rad;
}


Value Parameters
Absoft FORTRAN 77 provides the intrinsic function [%]val for passing value parameters. Although there is generally no need to pass a value directly to a FORTRAN procedure, these functions may be used to pass a value to a C function:

WRITE (*,*) 'Enter an integer:'
READ (*,*) i
CALL c_fun(VAL(i))
END


void c_fun(i) int i; { printf ("%d is ", i); if (i % 2 == 0) printf ("even.\n"); else printf ("odd.\n"); }


The value of i will be passed directly to c_fun, and will be left unaltered upon return.


Value parameters can be passed from C to FORTRAN with use of the VALUE statement. The arguments which are passed by value are simply declared as VALUE.

void c_fun()
{
void fortran_sub();
int i;

     fortran_sub(i);
}




SUBROUTINE fortran_sub(i)
VALUE i
...
END


Note: C will pass all floating point data as double precision by default.

Indirection (the LOC Function)
The [%]loc function is provided to give one level of indirection. The argument to [%]loc must be a scalar name, an array name or the name of an external procedure. The function returns the address of its argument as a 32-bit integer.

This example illustrates the use of loc to pass an array. Note that this is a one-dimensional array. Due to the different ordering used by C and FORTRAN for arrays, multi-dimensional arrays cannot be freely passed and indexed between the languages:

INTEGER*4 ia(10)

CALL c_fun (LOC(ia))
WRITE(*,*) ia
END


void c_fun(i) int *i[10]; { int j; for(j=0; j<10; j++) (*i)[j] = j; }


Function Results
In order to obtain function results in FORTRAN from C language functions and vice versa, the functions must be typed equivalently in both languages: either INTEGER, REAL, DOUBLE PRECISION, RECORD, or POINTER. All other data types must be returned in reference parameters. The following are examples of the passing of function results between FORTRAN and C.

A Call to C from FORTRAN

PROGRAM callc
INTEGER*4 Cmax, A, B

WRITE (*,*) 'Enter two numbers:'
READ (*,*) A, B
WRITE (*,*) 'The largest of', A,' and', B,' is', Cmax(A,B)
END

int Cmax (x,y) int *x,*y; { return( (*x >= *y) ? *x : *y ); }


A Call to FORTRAN from C

main()
{
float qt_to_liters(), qt;
      printf ("Enter number of quarts:\n");
      scanf ("%f",&qt); printf("%f quarts = %f liters.\n", qt, qt_to_liters(&qt));
}


REAL*4 FUNCTION qt_to_liters(q) REAL*4 q qt_to_liters = q * 0.9461 END


Passing Strings to C
FORTRAN strings are a sequence of characters padded with blanks out to their full fixed length, while strings in C are a sequence or array of characters terminated by a null character. Therefore, when passing FORTRAN strings to C routines, eliminate the extra blanks and terminate them with a null character. The following FORTRAN expression will properly pass the FORTRAN string anystring to the C routine CPrint:

PROGRAM cstringcall
character*255 string
string = 'Moscow on the Hudson'
CALL CPrint(TRIM(string)//CHAR(0))
END




void CPrint (anystring)
char *anystring[];
{
     printf ("%s\n",anystring);
}


This example will neatly output "Moscow on the Hudson". If the trim function was not used, the same string would be printed, but followed by 235 blanks. If the char(0) was omitted, C would print characters until a null character was encountered, whenever that might be.


In Absoft FORTRAN, the -K option may be used to allow embedded escape sequences in strings. The sequence for a null "\0" may be used to pass string constants as argument:

character*15 Fstring
CALL CPrint("string constant\0") ! null terminated string

Fstring = "string constant" ! blank padded string
CALL CPrint(TRIM(Fstring)//"\0") ! append a null

Calling FORTRAN Math Routines
All of the FORTRAN intrinsic math functions which return values recognized by the C language can be called directly from C as long as the FORTRAN runtime library, NTF77.LIB, is linked to the application. All arguments are passed by value. The names of the functions which can be called are formed by taking the specific intrinsic function names in lower case and adding two underscores to the beginning. The following example calls the FORTRAN intrinsic function SIN directly from C:

main()
{
float sin_of_a, a, __sin();

      a = 3.1415926/6;
      sin_of_a = __sin(a);
}


Calling FORTRAN I/O Routines
There are no restrictions on calling FORTRAN subroutines which perform I/O from C. The FORTRAN I/O library is completely re-entrant and requires no initialization. The only requirement is that all files opened in FORTRAN must be explicitly closed in FORTRAN before exiting to the system. FORTRAN unit numbers may not be used as C file descriptors and vice versa. Refer to Chapter 12, Input/Output and FORMAT Specification, for a description of I/O in Absoft FORTRAN 77.

Naming Conventions
Global names in FORTRAN include procedure names and COMMON block names, both of which are significant to 31 characters. All global names are case sensitive, meaning the compiler recognizes the difference between upper and lower case characters. Use of the -f option will fold global names to lower case, while the -N109 option will fold global names to upper case. All other symbols in FORTRAN are manipulated as addresses or offsets from local labels and are invisible to the linker.


Procedure Names
Names of functions and subroutines in FORTRAN programs will appear in the assembly language source output or object file records as they were typed in the source code with a period prefix character attached. Symbolic names in the C language are case sensitive, distinguishing between upper and lower case characters. To make FORTRAN code compatible with C, avoid using the -f or -N109 options when compiling the FORTRAN source code.

Accessing COMMON Blocks from C
COMMON block names are formed in Absoft FORTRAN 77 by adding the characters "_C" to the beginning of the name of the common block. COMMON block names are case sensitive unless either the -f or -N109 options are specified at compile-time. The elements of the COMMON block can be accessed from the C language by declaring an external structure using this name.

For example:

COMMON /comm/ a,b,c


can be accessed in with the global declaration:

extern struct {
            float a;
            float b;
            float c;
            } _Ccomm;


Declaring C Structures In FORTRAN
If there are equivalent data types in FORTRAN for all elements of a C structure, a RECORD can be declared in FORTRAN to match the structure in C:

C                        FORTRAN

struct str {              STRUCTURE /str/
char c;                     CHARACTER c
long l;                     INTEGER*4 l
float f;                    REAL*4 f
double d;                   REAL*8 d
};                        END STRUCTURE
struct str my_struct;     RECORD /str/ my_struct


By default, the alignment of the C structure should be identical to the FORTRAN RECORD. Refer to the Specification and DATA Statements chapter of the FORTRAN 77 Language Reference Manual for more information on the FORTRAN RECORD type.