|
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.
|