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);
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License