To understand how to pass arguments between Sun FORTRAN and C programs, it is necessary to understand the possible methods that the operating system can use for passing arguments and how each language makes use of them. There are three ways that an actual argument may be passed to a subroutine. What is actually passed as an argument should always be a four byte word. It is the interpretation of that word that is where the differences arise.
Sun FORTRAN passes all data types other than CHARACTER by reference, i.e. the address of the variable or array is put in the argument list. CHARACTER variables are passed by a mixture of reference and value. The argument list contains the address of the character variable being passed, but there is also an extra argument added at the end of the argument list for each character variable. This gives the actual length of the FORTRAN CHARACTER variable and so this datum is being passed by value. These extra arguments are hidden from the FORTRAN programmer, but must be explicitly included in any C routines.
C uses call by value to pass all variables, constants (except string constants), expressions, array elements, structures and unions that are actual arguments of functions. It uses call by reference to pass whole arrays, string constants and functions. C never uses call by descriptor as a default.
To pass a C variable of type double by value requires the use of two longwords in the argument list. Similarly, if a C structure is passed by value, then the number of bytes that it takes up in the argument list can be large. This is a dangerous practice and all structures should be passed by reference. Since, by default, Sun FORTRAN does not pass variables by value anyway, this should not give rise to any problems.
In Sun FORTRAN, the default argument passing mechanism can be overridden by use of the %VAL and %REF functions. These functions are not portable and should be avoided whenever possible. The %DESCR function provided in VAX FORTRAN is not provided on a Sun. In C there is no similar way of ``cheating'' as there is in FORTRAN; however, this is not necessary as the language allows more flexibility itself. For example, if you wish to pass a variable named x by reference rather than by value, you simply put &x as the actual argument instead of x.
Since C provides more flexibility in the mechanism of passing arguments than does FORTRAN, it is C that ought to shoulder the burden of handling the different mechanisms. All numeric variables and constants, array elements, whole arrays and function names should be passed into and out of C functions by reference. Numeric expressions will be passed from FORTRAN to C by reference and so the corresponding dummy argument in the C function should be declared to be of type ``pointer to type''. When C has a constant or an expression as an actual argument in a function call, it can only pass it by value. Sun FORTRAN cannot cope with this and so in a C program, all expressions should be assigned to variables before being passed to a FORTRAN routine.
Here are some examples to illustrate these points.
PROGRAM FORT1 INTEGER A REAL B A = 1 B = 2.0 CALL C1( A, B ) ENDC function:
void c1_( int *a, float *b) { int x; float y; x = *a; /* x is now equal to 1 */ y = *b; /* y is now equal to 2.0 */ printf( "x = %d\n", x ); printf( "y = %f\n", y ); }
The C function name requires the underscore as the FORTRAN compiler generates this automatically.
In this first example, a Sun FORTRAN program passes an INTEGER and REAL variable to a C function. The values of these arguments are then assigned to two local variables. They could just as well have been used directly in the function by referring to the variables *a and *b instead of assigning their values to the local variables x and y. Since the FORTRAN program passes the actual arguments by reference, the dummy arguments used in the declaration of the C function should be a pointer to the variable that is being passed.
Now an example of calling a Sun FORTRAN subroutine from C.
main() { int i = 2; /* Declare i and initialize it. */ void fort2_( int *i ); /* Declare function fort2_. */ fort2_( &i ); /* Call fort2. */ }FORTRAN subroutine:
SUBROUTINE FORT2( I ) INTEGER I PRINT *,I END
The C main function declares and initializes a variable, i, and declares a function fort2_ (note the underscore). It calls fort2_, passing the address of the variable i rather than its value, as this is what the FORTRAN subroutine will be expecting.
As we have seen, the case of scalar numeric arguments is fairly straightforward, however, the passing of character variables between Sun FORTRAN and C is more complicated. Sun FORTRAN passes character variables by passing the address of the character variable and then adding an extra value to the argument list that is the size of the character variable. Furthermore, there is the point that FORTRAN deals with fixed-length, blank-padded strings, whereas C deals with variable-length, null-terminated strings. The simplest possible example of a character argument is given here as an illustration. Don't worry if it looks complicated, the F77 macros hide all of these details from the programmer, and in a portable manner as well!
PROGRAM FORT3 CHARACTER STR*20 CALL C3( STR ) PRINT *,STR ENDC function:
#include <stdio.h> /* Standard I/O functions */ void c3_( char *fortchar, int length ) { int i; /* A loop counter */ char *string = "This is a string"; /* A string to be printed */ /* Copy the string to the function argument */ strncpy( fortchar, string, length ); /* Pad the character argument with trailing blanks */ for( i = strlen( string ) ; i < length ; i++ ) fortchar[i] = ' '; }
The second variable declaration in the C subprogram declares a local variable to be a string and initializes it. This string is then copied to the storage area that the subprogram argument points to, taking care not to copy more characters than the argument has room for. Finally any remaining space in the argument is filled with blanks, the null character being overwritten. You should always fill any trailing space with blanks in this way.
CNF and F77 Mixed Language Programming -- FORTRAN and C