LF Fortran 95  

Argument Passing

Traditionally, Fortran compilers arrange for arguments to subroutines to be passed by reference. This means that the address is passed (pushed on the stack, in the case of PCs) and so the called routine has full access to the variable in the caller, and can read or write to that location.

C compilers, on the other hand, pass simple (i.e., scalar) variables by value, meaning that the current value of that variable is pushed, rather than its address. The function that is called can thus read, but cannot change, the variable in the caller. More complicated objects, such as arrays and structures, are passed by reference by C compilers. (Confusion over which symbols represent values, and which addresses, is a common source of bugs in C programs, and so you should check your usage carefully.)

Trying to connect a Fortran caller to a C callee thus requires that one bridge these two conventions. It is possible to do this either by modifying the Fortran part or the C portion of the calling interface. Since LF95 is a Fortran package, in the examples that follow we will leave the Fortran form alone and modify the C side. This essentially means that C functions should be set up so as to expect that all visible arguments are being passed by reference, or "as pointers" in the C lingo.

Passing Arrays in C or C++

Because C processes arrays as an array of arrays and Fortran processes arrays as multi-dimensional arrays, there are some special considerations in processing a Fortran array. Excluding a single-dimension array (which is stored the same in C as in Fortran), you will need to reverse the indices when accessing a Fortran array in C. The reason for this is that in C, the right-most index varies most quickly and in Fortran the left-most index varies most quickly (multi-dimensional). In an array of arrays, the columns are stored sequentially: row 1-column 1 is followed by row 1-column 2, etc. In a multi-dimensional array, the rows are stored sequentially: row 1-column 1 is followed by row 2-column 1, etc.

Also note that all C arrays start at 0. We do not recommend that you use a lower dimension bound other than zero (0) as your C code will have to modify the indices based on the value used. We strongly recommend that you do not use negative lower and upper dimension bounds!

If the subscript ranges are not known at compile time, they can be passed at runtime, but you will have to provide the code to scale the indices to access the proper members of the array.

Some sample code may help explain the array differences. Your Fortran code would look like:

subroutine test(real_array)
real :: real_array(0:4,0:5,0:6,0:7,0:8,0:9,0:10)
integer :: i,j,k,l,m,n,o
do o = 0, 10
 do n = 0, 9
  do m = 0, 8
   do l = 0, 7
    do k = 0, 6
     do j = 0, 5
      do i = 0, 4
       real_array(i,j,k,l,m,n,o) = 12.00
      end do
     end do
    end do
   end do
  end do
 end do
end do
end subroutine test

The equivalent C code would look like:

void test(float real_array[10][9][8][7][6][5][4])
  int i,j,k,l,m,n,o;
  /*  ** this is what the subscripts would look like on the C side
  for(o = 0; o < 11; o++)
    for(n = 0; n < 10; n++)
      for(m = 0; m < 9; m++)
        for(l = 0; l < 8; l++)
          for(k = 0; k < 7; k++)
            for(j = 0; j < 6; j++)
              for(i = 0; i < 5; i++)
                real_array[o][n][m][l][k][j][i] = 12.000;

On the Fortran side of the call, the array argument must not be dimensioned as an assumed-shape array. You should use explicit shape, assumed size, or automatic arrays.