| Cray C and C++ Reference Manual - S-2179-52 | ||
|---|---|---|
| Prev Section | Chapter 13. Interlanguage Communication | Next Section |
This subsection describes the following aspects of calling Fortran from C or C++. Topics include requirements and guidelines, argument passing, array storage, logical and character data, accessing named common, and accessing blank common.
Keep the following points in mind when calling Fortran functions from C or C++:
Fortran uses the call-by-address convention. C and C++ use the call-by-value convention, which means that only pointers should be passed to Fortran subprograms. See Section 13.3.2.
Fortran arrays are in column-major order. C and C++ arrays are in row-major order. This indicates which dimension is indicated by the first value in an array element subscript. See Section 13.3.3.
Single-dimension arrays of signed 32-bit integers and single dimension arrays of 32-bit floating-point numbers are the only aggregates that can be passed as parameters without changing the arrays.
Fortran character pointers and character pointers from Cray C and C++ are incompatible. See Section 13.3.4.
Fortran logical values and the Boolean values from C and C++ are not fully compatible. See Section 13.3.4.
External C and C++ variables are stored in common blocks of the same name, making them readily accessible from Fortran programs if the C or C++ variable is in uppercase.
When declaring Fortran functions or objects in C or C++, the name must be specified in all uppercase letters, digits, or underscore characters and consist of 31 or fewer characters.
In Cray C, Fortran functions can be declared using the fortran keyword (see Section 9.2). The fortran keyword is not available in Cray C++. Instead, Fortran functions must be declared by specifying extern "C".
Because Fortran subroutines expect arguments to be passed by pointers rather than by value, C and C++ functions called from Fortran subroutines must pass pointers rather than values.
All argument passing in Cray C is strictly by value. To prepare for a function call between two Cray C functions, a copy is made of each actual argument. A function can change the values of its formal parameters, but these changes cannot affect the values of the actual arguments. It is possible, however, to pass a pointer. (All array arguments are passed by this method.) This capability is analogous to the Fortran method of passing arguments.
In addition to passing by value, Cray C++ also provides passing by reference.
C and C++ arrays are stored in memory in row-major order. Fortran arrays are stored in memory in column-major order. For example, the C or C++ array declaration int A[3][2] is stored in memory as:
The previously defined array is viewed linearly in memory as:
A[0][0] A[0][1] A[1][0] A[1][1] A[2][0] A[2][1] |
The Fortran array declaration INTEGER A(3,2) is stored in memory as:
The previously defined array is viewed linearly in memory as:
A(1,1) A(2,1) A(3,1) A(1,2) A(2,2) A(3,2) |
When an array is shared between Cray C, C++, and Fortran, its dimensions are declared and referenced in C and C++ in the opposite order in which they are declared and referenced in Fortran. Arrays are zero-based in C and C++ and are one-based in Fortran, so in C and C++ you should subtract 1 from the array subscripts that you would normally use in Fortran.
For example, using the Fortran declaration of array A in the preceding example, the equivalent declaration in C or C++ is:
int a[2][3]; |
The following list shows how to access elements of the array from Fortran and from C or C++:
| Fortran | C or C++ | |
| A(1,1) | A[0][0] | |
| A(2,1) | A[0][1] | |
| A(3,1) | A[0][2] | |
| A(1,2) | A[1][0] | |
| A(2,2) | A[1][1] | |
| A(3,2) | A[1][2] |
Logical and character data need special treatment for calls between C or C++ and Fortran. Fortran has a character descriptor that is incompatible with a character pointer in C and C++. The techniques used to represent logical (Boolean) values also differ between Cray C, C++, and Fortran.
Mechanisms you can use to convert one type to the other are provided by the fortran.h header file and conversion macros shown in the following list:
The following example demonstrates how external C and C++ variables are accessible in Fortran named common blocks. It shows a C or C++ C function calling a Fortran subprogram, the associated Fortran subprogram, and the associated input and output.
In this example, the C or C++ structure ST is accessed in the Fortran subprogram as common block ST. The name of the structure and the Fortran common block must match. Note that this requires that the structure name be uppercase. The C and C++ C structure member names and the Fortran common block member names do not have to match, as is shown in this example.
The following Cray C main program calls the Fortran subprogram FCTN:
#include <stdio.h>
struct
{
int i;
double a[10];
long double d;
} ST;
main()
{
int i;
/* initialize struct ST */
ST.i = 12345;
for (i = 0; i < 10; i++)
ST.a[i] = i;
ST.d = 1234567890.1234567890L;
/* print out the members of struct ST */
printf("In C: ST.i = %d, ST.d = %20.10Lf\n", ST.i, ST.d);
printf("In C: ST.a = ");
for (i = 0; i < 10; i++)
printf("%4.1f", ST.a[i]);
printf("\n\n");
/* call the fortran function */
FCTN();
} |
The following example is the Fortran subprogram FCTN called by the previous Cray C main program:
C *********** Fortran subprogram (f.f): ***********
SUBROUTINE FCTN
COMMON /ST/STI, STA(10), STD
INTEGER STI
REAL STA
DOUBLE PRECISION STD
INTEGER I
WRITE(6,100) STI, STD
100 FORMAT ('IN FORTRAN: STI = ', I5, ', STD = ', D25.20)
WRITE(6,200) (STA(I), I = 1,10)
200 FORMAT ('IN FORTRAN: STA =', 10F4.1)
END |
The previous Cray C and Fortran examples are executed by the following commands, and they produce the output shown:
% cc -c c.c % ftn -c f.f % ftn c.o f.o % ./a.out ST.i = 12345, ST.d = 1234567890.1234567890 In C: ST.a = 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 IN FORTRAN: STI = 12345, STD = .12345678901234567889D+10 IN FORTRAN: STA = 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 |
Fortran includes the concept of a common block. A common block is an area of memory that can be referenced by any program unit in a program. A named common block has a name specified in names of variables or arrays stored in the block. A blank common block, sometimes referred to as blank common, is declared in the same way, but without a name.
There is no way to access blank common from C or C++ similar to accessing a named common block. However, you can write a simple Fortran function to return the address of the first word in blank common to the C or C++ program and then use that as a pointer value to access blank common.
The following example shows how Fortran blank common can be accessed using C or C++ source code:
#include <stdio.h>
struct st
{
float a;
float b[10];
} *ST;
#ifdef __cplusplus
extern "C" struct st *MYCOMMON(void);
extern "C" void FCTN(void);
#else
fortran struct st *MYCOMMON(void);
fortran void FCTN(void);
#endif
main()
{
int i;
ST = MYCOMMON();
ST->a = 1.0;
for (i = 0; i < 10; i++)
ST->b[i] = i+2;
printf("\n In C and C++\n");
printf(" a = %5.1f\n", ST->a);
printf(" b = ");
for (i = 0; i < 10; i++)
printf("%5.1f ", ST->b[i]);
printf("\n\n");
FCTN();
} |
This Fortran source code accesses blank common and is accessed from the C or C++ source code in the preceding example:
SUBROUTINE FCTN COMMON // STA,STB(10) PRINT *, "IN FORTRAN" PRINT *, " STA = ",STA PRINT *, " STB = ",STB STOP END FUNCTION MYCOMMON() COMMON // A MYCOMMON = LOC(A) RETURN END |
This is the output of the previous C or C++ source code:
a = 1.0 b = 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 |
This is the output of the previous Fortran source code:
STA = 1. STB = 2., 3., 4., 5., 6., 7., 8., 9., 10., 11. |
Here is an example of a Cray C function that calls a Fortran subprogram. The Fortran subprogram example follows the Cray C function example, and the input and output from this sequence follows the Fortran subprogram example.
Note: This example assumes that the Cray Fortran function is compiled with the -s default32 option enabled. The examples will not work if the -s default64 option is enabled.
/* C program (main.c): */
#include <stdio.h>
#include <string.h>
#include <fortran.h>
/* Declare prototype of the Fortran function. Note the last */
/* argument passes the length of the first argument. */
fortran double FTNFCTN (char *, int *, int);
double FLOAT1 = 1.6;
double FLOAT2; /* Initialized in FTNFCTN */
main()
{
int clogical, ftnlogical, cstringlen;
double rtnval;
char *cstring = "C Character String";
/* Convert clogical to its Fortran equivalent */
clogical = 1;
ftnlogical = _btol(clogical);
/* Print values of variables before call to Fortran function */
printf(" In main: FLOAT1 = %g; FLOAT2 = %g\n",
FLOAT1, FLOAT2);
printf(" Calling FTNFCTN with arguments:\n");
printf(" string = \"%s\"; logical = %d\n\n", cstring, clogical);
cstringlen = strlen(cstring);
rtnval = FTNFCTN(cstring, &ftnlogical, cstringlen);
/* Convert ftnlogical to its C equivalent */
clogical = _ltob(&ftnlogical);
/* Print values of variables after call to Fortran function */
printf(" Back in main: FTNFCTN returned %g\n", rtnval);
printf(" and changed the two arguments:\n");
printf(" string = \"%.*s\"; logical = %d\n",
cstringlen, cstring, clogical);
} |
C Fortran subprogram (ftnfctn.f):
FUNCTION FTNFCTN(STR, LOG)
REAL FTNFCTN
CHARACTER*(*) STR
LOGICAL LOG
COMMON /FLOAT1/FLOAT1
COMMON /FLOAT2/FLOAT2
REAL FLOAT1, FLOAT2
DATA FLOAT2/2.4/ ! FLOAT1 INITIALIZED IN MAIN
C PRINT CURRENT STATE OF VARIABLES
PRINT*, ' IN FTNFCTN: FLOAT1 = ', FLOAT1,
1 ';FLOAT2 = ', FLOAT2
PRINT*, ' ARGUMENTS: STR = "', STR, '"; LOG = ', LOG
C CHANGE THE VALUES FOR STR(ING) AND LOG(ICAL)
STR = 'New Fortran String'
LOG = .FALSE.
FTNFCTN = 123.4
PRINT*, ' RETURNING FROM FTNFCTN WITH ', FTNFCTN
PRINT*
RETURN
END |
The previous Cray C function and Fortran subprogram are executed by the following commands and produce the following output:
% cc -c main.c % ftn -c ftnfctn.f % ftn main.o ftnfctn.o % ./a.out In main: FLOAT1 = 1.6; FLOAT2 = 2.4 Calling FTNFCTN with arguments: string = "C Character String"; logical = 1 IN FTNFCTN: FLOAT1 = 1.6; FLOAT2 = 2.4 ARGUMENTS: STR = "C Character String"; LOG = T RETURNING FROM FTNFCTN WITH 123.4 Back in main: FTNFCTN returned 123.4 and changed the two arguments: string = "New Fortran String"; logical = 0 |
The following example illustrates how a Fortran program can be called from a Cray C++ program:
#include <iostream.h>
extern "C" int FORTRAN_ADD_INTS(int *arg1, int &arg2);
main()
{
int num1, num2, res;
cout << "Start C++ main" << endl << endl;
//Call FORTRAN function to add two integers and return result.
//Note that the second argument is a reference parameter so
//it is not necessary to take the address of the
//variable num2.
num1 = 10;
num2 = 20;
cout << "Before Call to FORTRAN_ADD_INTS" << endl;
res = FORTRAN_ADD_INTS(&num1, num2);
cout << "Result of FORTRAN Add = " << res << endl << endl;
cout << "End C++ main" << endl;
} |
The Fortran program that is called from the Cray C++ main function in the preceding example is as follows:
INTEGER FUNCTION FORTRAN_ADD_INTS(Arg1, Arg2) INTEGER Arg1, Arg2 PRINT *," FORTRAN_ADD_INTS, Arg1,Arg2 = ", Arg1, Arg2 FORTRAN_ADD_INTS = Arg1 + Arg2 END |
The output from the execution of the preceding example is as follows:
Start C++ main Before Call to FORTRAN_ADD_INTS FORTRAN_ADD_INTS, Arg1,Arg2 = 10, 20 Result of FORTRAN Add = 30 End C++ main |
| Prev Section | Table of Contents | Title Page | Index | Next Section |
| Calling Assembly Language Functions from a C or C++ Function | Up one level | Calling a C or C++ Function from a Fortran or Assembly Language Program |