Contained WithinFind More DocumentationFeatured Support Resources | Download this book in PDF (392 KB)
Chapter 11 C-Fortran InterfaceThis chapter treats issues regarding Fortran and C interoperability. The discussion is inherently limited to the specifics of the Sun FORTRAN 77, Fortran 90, and C compilers. Note - Material common to both Sun FORTRAN 77 and Fortran 90 is presented in examples that use FORTRAN 77. Compatibility IssuesMost C-Fortran interfaces must agree in all of these aspects:
Some C-Fortran interfaces must also agree on:
Function or Subroutine?The word function has different meanings in C and Fortran. Depending on the situation, the choice is important:
When a Fortran routine calls a C function:
When a C function calls a Fortran subprogram:
Data Type CompatibilityThe tables below summarize the data sizes and default alignments for FORTRAN 77 and Fortran 90 data types. In both tables, note the following:
FORTRAN 77 and C Data TypesTable 11-1 shows the sizes and allowable alignments for FORTRAN 77 data types. It assumes no compilation options affecting alignment or promoting default data sizes are applied. (See also the FORTRAN 77 Language Reference Manual). Table 11-1 Data Sizes and Alignments--(in Bytes) Pass by Reference (f77 and cc)
SPARC: Fortran 90 and C Data TypesThe following table similarly compares the Fortran 90 data types with C. Table 11-2 Data Sizes and Alignment--(in Bytes) Pass by Reference (f90 and cc)
Case SensitivityC and Fortran take opposite perspectives on case sensitivity:
The f77 and f90 default is to ignore case by converting subprogram names to lowercase. It converts all uppercase letters to lowercase letters, except within character-string constants. There are two usual solutions to the uppercase/lowercase problem:
Use one of these two solutions, but not both. Most examples in this chapter use all lowercase letters for the name in the C function, and do not use the f77 -U compiler option. (f90 does not have an equivalent option.) Underscores in Routine NamesThe Fortran compiler normally appends an underscore (_) to the names of subprograms appearing both at entry point definition and in calls. This convention differs from C procedures or external variables with the same user-assigned name. If the name has exactly 32 characters, the underscore is not appended. All Fortran library procedure names have double leading underscores to reduce clashes with user-assigned subroutine names. There are three usual solutions to the underscore problem:
Use only one of these solutions. The examples in this chapter could use the FORTRAN 77 C() compiler pragma to avoid underscores. The C() pragma directive takes the names of external functions as arguments. It specifies that these functions are written in the C language, so the Fortran compiler does not append an underscore as it ordinarily does with external names. The C()directive for a particular function must appear before the first reference to that function. It must also appear in each subprogram that contains such a reference. The conventional usage is: EXTERNAL ABC, XYZ !$PRAGMA C( ABC, XYZ ) If you use this pragma, the C function does not need an underscore appended to the function name. Fortran 90 does not have equivalent methods for avoiding underscores. Trailing underscores are required in the names of C routines called from Fortran 90 routines. Argument-Passing by Reference or ValueIn general, Fortran routines pass arguments by reference. In a call, if you enclose an argument with the f77 and f90 nonstandard function %VAL(), the calling routine passes it by value. In general, C passes arguments by value. If you precede an argument by the ampersand operator (&), C passes the argument by reference using a pointer. C always passes arrays and character strings by reference. Argument OrderExcept for arguments that are character strings, Fortran and C pass arguments in the same order. However, for every argument of character type, the Fortran routine passes an additional argument giving the length of the string. These are long int quantities in C, passed by value. The order of arguments is:
This Fortran code fragment:
Is equivalent to this in C:
CHARACTER*7 S
INTEGER B(3)
...
CALL SAM( S, B(2) )
char s[7];
long b[3];
...
sam_( s, &b[1], 7L ) ;
Array Indexing and OrderArray indexing and order differ between Fortran and C. Array IndexingC arrays always start at zero, but by default Fortran arrays start at 1. There are two usual ways of approaching indexing.
Array OrderFortran arrays are stored in column-major order: A(3,2) A(1,1) A(2,1) A(3,1) A(1,2) A(2,2) A(3,2) A(1,3) A(2,3) A(3,3) C arrays in row-major order: A[3][2] A[0][0] A[0][1] A[0][2] A[1][0] A[1][1] A[1][2] A[2][0] A[2][1] A[2][2] For one-dimensional arrays, this is no problem. For two-dimensional and higher arrays, be aware of how subscripts appear and are used in all references and declarations--some adjustments might be necessary. For example, it may be confusing to do part of a matrix manipulation in C and the rest in Fortran. It might be preferable to pass an entire array to a routine in the other language and perform all the matrix manipulation in that routine to avoid doing part in C and part in Fortran. File Descriptors and stdioFortran I/O channels are in terms of unit numbers. The I/O system does not deal with unit numbers but with file descriptors. The Fortran runtime system translates from one to the other, so most Fortran programs do not have to recognize file descriptors. Many C programs use a set of subroutines, called standard I/O (or stdio). Many functions of Fortran I/O use standard I/O, which in turn uses operating system I/O calls. Some of the characteristics of these I/O systems are listed in in the following table. Table 11-3 Comparing I/O Between Fortran and C
File PermissionsC programs typically open input files for reading and output files for writing or for reading and writing. A f77 program can OPEN a file READONLY or with READWRITE='READ' or 'WRITE' or 'READWRITE'. f90 supports the READWRITE specifier, but not READONLY. Fortran tries to open a file with the maximum permissions possible, first for both reading and writing, then for each separately. This event occurs transparently and is of concern only if you try to perform a READ, WRITE, or ENDFILE operation but you do not have permission. Magnetic tape operations are an exception to this general freedom, since you can have write permissions on a file, but not have a write ring on the tape. Libraries and Linking With the f77 or f90 CommandTo link the proper Fortran and C libraries, use the f77 or f90 command to invoke the linker. demo% cc -c RetCmplxmain.c demo% f77 RetCmplx.f RetCmplxmain.o ¨ This command line does the linking. demo% a.out 4.0 4.5 8.0 9.0 demo% Passing Data Arguments by ReferenceThe standard method for passing data between Fortran routines and C procedures is by reference. To a C procedure, a Fortran subroutine or function call looks like a procedure call with all arguments represented by pointers. The only peculiarity is the way Fortran handles character strings and functions as arguments and as the return value from a CHARACTER*n function. Simple Data TypesFor simple data types (not COMPLEX or CHARACTER strings), define or pass each associated argument in the C routine as a pointer:. Table 11-4 Passing Simple Data Types
COMPLEX DataPass a Fortran COMPLEX data item as a pointer to a C struct of two float or two double data types: Table 11-5 Passing COMPLEX Data Types
In 64-bit environments and compiling with -xarch=v9, COMPLEX values are returned in registers. Character StringsPassing strings between C and Fortran routines is not recommended because there is no standard interface. However, note the following:
A Fortran call with a character string argument is shown in the next example with its C equivalent: Table 11-6 Passing a CHARACTER string
If the length of the string is not needed in the called routine, the extra arguments may be ignored. However, note that Fortran does not automatically terminate strings with the explicit null character that C expects. This must be added by the calling program. One-Dimensional ArraysArray subscripts in C start with 0. Table 11-7 Passing a One-Dimensional Array
Two-Dimensional ArraysRows and columns between C and Fortran are switched. Table 11-8 Passing a Two-Dimensional Array
StructuresC and FORTRAN 77 structures and Fortran 90 derived types can be passed to each other's routines as long as the corresponding elements are compatible. Table 11-9 Passing FORTRAN 77 STRUCTURE Records
Table 11-10 Passing Fortran 90 Derived Types
PointersA FORTRAN 77 pointer can be passed to a C routine as a pointer to a pointer because the Fortran routine passes arguments by reference. Table 11-11 Passing a FORTRAN 77 POINTER
C pointers are compatible with Fortran 90 (release 2.0) scalar pointers, but not array pointers. Passing Data Arguments by ValueCall by value is available only for simple data with FORTRAN 77, and only by Fortran routines calling C routines. There is no way for a C routine to call a Fortran routine and pass arguments by value. It is not possible to pass arrays, character strings, or structures by value. These are best passed by reference. Use the nonstandard Fortran function %VAL(arg) as an argument in the call. In the following example, the Fortran routine passes x by value and y by reference. The C routine incremented both x and y, but only y is changed. Table 11-12 Passing Simple Data Arguments by Value: FORTRAN 77 Calling C
Functions That Return a ValueA Fortran function that returns a value of type BYTE (FORTRAN 77 only), INTEGER, REAL, LOGICAL, DOUBLE PRECISION, or REAL*16 (SPARC only) is equivalent to a C function that returns a compatible type (see Table 11-1 and Table 11-2). There are two extra arguments for the return values of character functions, and one extra argument for the return values of complex functions. Returning a Simple Data TypeThe following example returns a REAL or float value. BYTE, INTEGER, LOGICAL, DOUBLE PRECISION, and REAL*16 are treated in a similar way: Table 11-13 Functions Returning a REAL or float Value
Returning COMPLEX DataA Fortran function returning COMPLEX or DOUBLE COMPLEX is equivalent to a C function with an additional first argument that points to the return value in memory. The general pattern for the Fortran function and its corresponding C function is:
Table 11-14 Function Returning COMPLEX Data
In 64-bit environments and compiling with -xarch=v9, COMPLEX values are returned in floating-point registers: COMPLEX and DOUBLE COMPLEX in %f0 and %f1, and COMPLEX*32 in %f0, %f1, %f2, and %f3. Returning a CHARACTER StringPassing strings between C and Fortran routines is not encouraged. However, a Fortran character-string-valued function is equivalent to a C function with two additional first arguments--data address and string length. The general pattern for the Fortran function and its corresponding C function is:
Here is an example: Table 11-15 A Function Returning a CHARACTER String
In this example, the C function and calling C routine must accommodate two initial extra arguments (a pointer to the result string and the length of the string) and one additional argument at the end of the list (length of character argument). Note that in the Fortran routine called from C, it is necessary to explicitly add a final null character. Labeled COMMONFortran labeled COMMON can be emulated in C by using a global struct. Table 11-16 Emulating Labeled COMMON
Note that the external name established by the C routine must end in an underscore to link with the block created by the Fortran program. Note also that the C directive #pragma pack may be needed to get the same padding as with Fortran. Both f77 and f90 align data in COMMON blocks to at most 4-byte boundaries. Sharing I/O Between Fortran and CMixing Fortran I/O with C I/O (issuing I/O calls from both C and Fortran routines) is not recommended. It is better to do all Fortran I/O or all C I/O, not both. The Fortran I/O library is implemented largely on top of the C standard I/O library. Every open unit in a Fortran program has an associated standard I/O file structure. For the stdin, stdout, and stderr streams, the file structure need not be explicitly referenced, so it is possible to share them. If a Fortran main program calls C to do I/O, the Fortran I/O library must be initialized at program startup to connect units 0, 5, and 6 to stderr, stdin, and stdout, respectively. The C function must take the Fortran I/O environment into consideration to perform I/O on open file descriptors. However, if a C main program calls a Fortran subprogram to do I/O, the automatic initialization of the Fortran I/O library to connect units 0, 5, and 6 to stderr, stdin, and stdout is lacking. This connection is normally made by a Fortran main program. If a Fortran function attempts to reference the stderr stream (unit 0) without the normal Fortran main program I/O initialization, output will be written to fort.0 instead of to the stderr stream. The C main program can initialize Fortran I/O and establish the preconnection of units 0, 5, and 6 by calling the f_init() FORTRAN 77 library routine at the start of the program and, optionally, f_exit() at termination. Remember: even though the main program is in C, you should link with f77. Alternate ReturnsFortran's alternate returns mechanism is obsolescent and should not be used if portability is an issue. There is no equivalent in C to alternate returns, so the only concern would be for a C routine calling a Fortran routine with alternate returns. The Sun Fortran implementation returns the int value of the expression on the RETURN statement. This is implementation dependent and its use should be avoided. Table 11-17 Alternate Returns
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||