C Fortran
A code example with some comments can be found below. I try to collect all possible connections between FORTRAN and C. This package has a C-lib, a C program to test the lib and the FORTRAN program that also accesses the lib.
File: Makefile
#
# Calling Fortran routines from C++. A sample
# GNU makefile
#
# Correia 27.04.2007
#
F77 = g77
F_FLAGS =
C++ = g++
C_FLAGS =
LIBS = -lg2c
F_LIBS = -lstdc++ -lfrtbegin -lg2c
all: fc1
clean:
rm -f c1.o libc1.a f1.o prog.o fc1 cProg
f1.o: GNUmakefile f1.f
$(F77) $(F_FLAGS) -c f1.f
c1.o: GNUmakefile c1.cpp
$(C++) $(C_FLAGS) -c c1.cpp
libc1.a:GNUmakefile c1.o
ar -rc libc1.a c1.o
ranlib libc1.a
rm c1.o
fc1: GNUmakefile f1.o libc1.a
$(F77) $(F_FLAGS) -o fc1 f1.o libc1.a $(F_LIBS)
rm libc1.a f1.o
prog.o:
$(C++) $(C_FLAGS) -c prog.cpp
cProg: GNUmakefile libc1.a prog.o
$(C++) $(C_FLAGS) prog.o -L. -lc1 -o cProg
rm libc1.a prog.o
File: prog.cpp
#include "c1.h" int main(void) { int a(2), b(11); int resp = multiply_(&a, &b); printresp_(&resp); return 0; }
File: f1.f
C *
C * These functions are writing as part of the studies of a C++ interface that
C * must be accessed by a Fortran program.
C * This FORTRAN code is compiled with a C static library. The used compiler
C * and command lines are:
C * g77 -c f1.f
C * g77 -o fc1 f1.o libc1.a -lstdc++ -lfrtbegin -lg2c
C *
C * Claudene Correia, c.correia@tu-bs.de, 27.04.2007
C *
PROGRAM FCALC
C used with the functions Multiply and PrintResp
INTEGER I
INTEGER J
INTEGER RESP1
C used with the function Divide
DOUBLE PRECISION A
DOUBLE PRECISION B
DOUBLE PRECISION RESP2
C used with the function Subtract
REAL X
REAL Y
REAL RESP3
C used with the function TestLogical
LOGICAL LO
LOGICAL RESP4
C used with the function DotProduct
INTEGER ArrayI(3)
INTEGER ArrayJ(3)
INTEGER RESP5
C used with the function CrossProduct
DOUBLE PRECISION ArrayA(3)
DOUBLE PRECISION ArrayB(3)
DOUBLE PRECISION ArrayRESP(3)
LOGICAL RESP6
C used with the functions Transpose and PrintMatrix
INTEGER ROW, COL
INTEGER MatrixA(4,2)
INTEGER MatrixB(2,4)
LOGICAL RESP7
C used with the functions PrintString and Int2String
CHARACTER*(20) Text
C used with the functions RessetId and PrintId
COMMON /ID/ PersonName, PersonAge, NameLength
CHARACTER*(60) PersonName
INTEGER PersonAge
INTEGER NameLength
EXTERNAL Multiply
EXTERNAL Divide
EXTERNAL Subtract
EXTERNAL TestLogical
EXTERNAL PrintResp
EXTERNAL DotProduct
EXTERNAL CrossProduct
EXTERNAL Transpose
EXTERNAL PrintMatrix
EXTERNAL PrintString
EXTERNAL Int2String
EXTERNAL RessetId
EXTERNAL PrintId
C the function return must be defined to avoid variable type error
INTEGER Multiply
DOUBLE PRECISION Divide
REAL Subtract
LOGICAL TestLogical
INTEGER DotProduct
LOGICAL CrossProduct
LOGICAL Transpose
CHARACTER*(20) Int2String
C ** START **
C send Integer to the C interface and receive integer
I=10
J=3
c RESP=I*J
RESP1=Multiply(I,J)
WRITE(*,*) 'F: The result from ', I,' * ',J,' = ', RESP1
CALL PrintResp(RESP1)
C send double precision to the C interface and receive double precision
A=10.0
B=3.0
RESP2=Divide(A,B)
WRITE(*,*) 'F: The result from ', I,' / ',J,' = ', RESP2
C send real to the C interface and receive a real
X=9.9
Y=3.6
RESP3=Subtract(X,Y)
WRITE(*,*) 'F: The result from ', I,' - ',J,' = ', RESP3
C send a logical to the C interface and receive a logical.
c LO=.TRUE.
LO=.FALSE.
RESP4=TestLogical(LO)
IF (RESP4.EQV.LO) THEN
WRITE(*,*) 'F: Logical variable is TRUE'
ELSE
WRITE(*,*) 'F: Logical variable is FALSE'
ENDIF
C send an array and receive a scalar
ArrayI(1)=10
ArrayI(2)=100
ArrayI(3)=1000
ArrayJ(1)=5
ArrayJ(2)=6
ArrayJ(3)=7
RESP5=DotProduct(ArrayI,3,ArrayJ,3)
CALL PrintResp(RESP5)
C send an array and receive an array by changing the argument variable
C ArrayResp3. The function return a logical that indicates success or not.
ArrayA(1)=1.0
ArrayA(2)=2.0
ArrayA(3)=3.0
ArrayB(1)=4.0
ArrayB(2)=5.0
ArrayB(3)=6.0
ArrayRESP(1)=0.
ArrayRESP(2)=0.
ArrayRESP(3)=0.
RESP6=CrossProduct(ArrayA,3, ArrayB,3, ArrayRESP,3)
IF (RESP6) THEN
WRITE(*,*) 'F: ( ', ArrayRESP(1), ' , ' , ArrayRESP(2),
* ' , ' , ArrayRESP(3) , ' )'
ENDIF
C Send a matrix to be printed by the C interface. A transpose matrix is also
C generated by the C interface, it will be returned in the argument variable
C MatrixB.
ROW=1
COL=1
DO WHILE (ROW.LE.4)
DO WHILE (COL.LE.2)
MatrixA(ROW,COL)=ROW + (COL-1) * 4
COL=COL+1
ENDDO
COL=1
ROW=ROW+1
ENDDO
CALL PrintMatrix(MatrixA,4,2)
RESP7=Transpose(MatrixA,4,2,MatrixB,2,4)
IF(RESP7)THEN
CALL PrintMatrix(MatrixB,2,4)
ENDIF
C use of strings. the '\0' must be written at the end to be in conform with
C the C format.
Text='Hallo Word !'
n=LEN_TRIM(Text)
Text=Text(1:n)//CHAR(0)
c Text=TRIM(Text)//CHAR(0)
CALL PrintString(Text)
C an integer is converted in String. This function has an particularity. The
C corresponding C function is:
C void int2string_(char* result, int length, int* a);
C the arguments result and length are inserted by the fortran compiler and
C let the fortran call to be:
C Text=Int2String(1234)
Text=Int2String(1234)
n=LEN_TRIM(Text)
Text=Text(1:n)//CHAR(0)
CALL PrintString(Text)
C The use of share memory between the C interface and the Fortran program.
C Using COMMON Blocks and C struct, both will share the same memory adress.
C Here the variables will be writting by the fortran and printed from the C
C interface. The function RessetId will erease the data writting by the fortran
C program.
CALL RessetId
CALL PrintId
WRITE(*,*) 'F: maximal number of characters is:', NameLength
PersonName='Antonio'
n=LEN_TRIM(PersonName)
PersonName=PersonName(1:n)//CHAR(0)
PersonAge=34
CALL PrintId
CALL RessetId
CALL PrintId
STOP
END
File: c1.h
/*! * These functions are writing as part of the studies of a C++ interface that * must be accessed by a Fortran program. * This C++ code is compiled with a C interface. The used compiler and * command lines are: * g++ -c c1.cpp * ar -rc libc1.a c1.o * ranlib libc1.a * * Claudene Correia, c.correia@tu-bs.de, 27.04.2007 */ /*! * Input from two integers (Fortran: INTEGER) and return a integer with the * result of a * b . */ extern "C" int multiply_(int* a, int* b); /*! * Input from two doubles (Fortran: DOUBLE PRECISION) and return a double with * the result of a / b . */ extern "C" double divide_(double* a, double* b); /*! * Input from two floats (Fortran: REAL) and return a float with the result * of a - b . */ extern "C" float subtract_(float*a, float*b); /*! * Test a Logical function. A Logical variable is treated as an integer, thus * the input is an integer (Fortran: LOGICAL). This function test if a is * 'TRUE' or 'FALSE' writting the result on the console and return a integer * with the value 'TRUE'. */ extern "C" int testlogical_(int*a); /*! * A simple print function that write the value of an integer on the console. */ extern "C" void printresp_(int* resp); /*! * An array of integers is received in the function argument (Fortran: * INTEGER variable(size)). This function computes and returns the dot product * from the arrays 'a' und 'b'. If the array dimension are not equal, 0 will * be returned. */ extern "C" int dotproduct_(int a[], int*sizea, int b[], int*sizeb); /*! * An array of doubles is worked here (Fortran: DOUBLE PRECISION var(size)). * The cross product for a 3D vector is computed and the result is returned * changing the argument variable 'resp'. If the array dimention is not 3, * FALSE will be returned, otherwise TRUE. */ extern "C" int crossproduct_(double* a, int* sizea, double* b, int* sizeb, double* resp, int* sizeResp); /*! * A 2D array is be manipulated (Fortran: INTEGER variable(row,col)) and * is read as a single array in C++. The number of rows and colls are used to * identify the element position in the matrix. The input matrix is accessed * by 'a' and the transpose are stored in b. * * Differences about Matrix in Fortran and C are explained into the cpp file. */ extern "C" int transpose_(int* a, int* rowsa, int* collsa, int* b, int* rowsb, int* collsb); /*! * A simple print function that works with a extra function to compute the * matrix element position with(i,j) in the array. See the description in * the cpp file. */ extern "C" void printmatrix_(int* a, int* rowsa, int* collsa); /*! * A simple function that write an input text in the console. * Fortran fill the string with ' ' after the last valid text character. C++ * need a '\0' character to especify the end of the text. Therefore an input * string muss have a '\0' character that should be included manually in the * Fortran code and an output string muss be filled with ' '. */ extern "C" void printstring_(char* text, int length); /*! * Convert an integer into string. The arguments 'result' and 'length' are * automatic included by the Fortran compiler. So the Fortran call will be: * character*(20) text * text=int2string(1231) * * See cpp file for more details. */ extern "C" void int2string_(char* result, int length, int* a); /*! * A struct is created the share memory with a Fortran program. * The function resetid_ will erase the values of the struct id_ writting * default data. * The function printid_ will write in the console the current values of the * struct id_. * * See cpp file for more details. */ extern struct setup id_; extern "C" void ressetid_(void); extern "C" void printid_(void);
File: c1.cpp
/*! * These functions are writing as part of the studies of a C++ interface that * must be accessed by a Fortran program. * This C++ code is compiled with a C interface. The used compiler and * command lines are: * g++ -c c1.cpp * ar -rc libc1.a c1.o * ranlib libc1.a * * Claudene Correia, c.correia@tu-bs.de, 27.04.2007 */ #include<iostream> #include "c1.h" int multiply_(int* a, int* b) { return (*a) * (*b); } double divide_(double* a, double* b) { return (*a) / (*b); } float subtract_(float*a, float*b) { return (*a) - (*b); } int testlogical_(int* a) { if(*a) printf(" C: test is TRUE.\n"); else printf(" C: test is FALSE.\n"); return true; } void printresp_(int* resp) { printf(" C: input value: %d\n", *resp); } int dotproduct_(int a[], int*sizea, int b[], int*sizeb) { int resp(0); if((*sizea) != (*sizeb)) return 0; for (int i(0); i < *sizea; i++) resp += a[i]*b[i]; return resp; } int crossproduct_(double* a, int* sizea, double* b, int* sizeb, double* resp, int* sizeResp) { if(((*sizea) != 3) || ((*sizeb) != 3) || ((*sizeResp) != 3)) return false; resp[0] = a[1] * b[2] - a[2] * b[1]; resp[1] = a[2] * b[0] - a[0] * b[2]; resp[2] = a[0] * b[1] - a[1] * b[0]; printf(" C: cross product: ( %f , %f , %f )\n",resp[0],resp[1],resp[2]); return true; } /*! * C stores each row contiguously in memory, while Fortran stores each column * contiguiusly. Mor over, for a N-dimensional array, in C the last dimension * is contiguous in memory, while Fortran the first dimension is contiguous. * * For example, the Fortran arrayt 'double precision A(2,3)' is stored in * memory like this: * A(1,1) A(2,1) A(1,2) A(2,2) A(1,3) A(2,3) * while the C array double A[2][3]' is stored in memory like this: * A[0][0] A[0][1] A[0][2] A[1][0] A[1][1] A[1][2] * * Note: * All matrices are written in continuous memory space and can be accessed * as an 1D Array. * As described above C and Fortran work in a different manner. C write * line by line instead of Fortran that write columns. In this way, the * element position in a 1D array should be calculated respecting the * Fortran construction. */ int transpose_(int* a, int* rowsa, int* collsa, int* b, int* rowsb, int* collsb) { if(((*rowsa) != (*collsb)) || ((*collsa) != (*rowsb))) return false; for(int i(0); i < (*rowsa); i++) for(int j(0); j < (*collsa); j++) b[ j + i * (*collsa) ] = a[ i + j * (*rowsa) ]; return true; } /*! * The matrix element position in the 1D array is calculated by a pre-defined * makro that helps the code development where the matrix element is accessed * using the position (i, j). */ #define O(i,j) ( i + j * (*rowsa)) void printmatrix_(int* a, int* rowsa, int* collsa) { printf(" C:\n"); for(int i(0); i < (*rowsa); i++){ for(int j(0); j < (*collsa); j++) //printf(" | %d", a[ i + j * (*rowsa) ] ); printf(" | %d", a[ O(i, j) ] ); printf(" |\n"); } printf("\n"); } void printstring_(char* text, int length) { printf(" C: %s\n", text); } /*! * Returning Character data types form C to Fortran * The C function must be void and the first two arguments a char* and int, * corresponding to the result string and the string length. The Fortran code * will be: * character*(20) text * character*(20) int2string * * text=int2string(1231) * * Note: * - Length and result do not appear in the Fortran call statement, they * are added by the compiler * - The maximum number of characters from result is length * - If fewer than length characters are returned, the return location * should be padded on the right with blanks. Fortran does not use zeros * to terminate strings. * - The called procedure is type void */ void int2string_(char* result, int length, int* a) { for(int i(0); i < length; i++) result[i]=' '; sprintf(result, "%d", *a); } /*! * A struct is created to share memory with a Fortran program. In Fortran it * will be build as a COMMON Block. * COMMON /ID/ PersonName, PersonAge, NameLength * CHARACTER*(60) PersonName * INTEGER PersonAge * INTEGER NameLength * in C it will be referencied as an external variable. * struct setup {...}; * extern struct setup id_; * * Note: use of extern requires that the common block be referenced first by * FORTRAN. If referenced first by C then drop the extern. The extern * statement states that it is trying to reference memory which has already * been set aside elsewhere. "yolinux.com" */ struct setup { char name[60]; int age; int namesize; }; void ressetid_(void) { sprintf(id_.name,"noName"); id_.namesize=60; id_.age=0; } void printid_(void) { printf(" C: %s, %d\n",id_.name, id_.age); }
page revision: 2, last edited: 11 Mar 2010 12:16