CVApp Forum@View topic - Advanced Array-Passing in Fortran

Advanced Array-Passing in Fortran

C,C++,Java Script, Python

Advanced Array-Passing in Fortran

Postby thomas » 2015年 Jun 10日, 17:36

http://michaelgoerz.net/notes/advanced-array-passing-in-fortran.html
Code: Select all
program test
  implicit none
  integer :: test_array1(10)
  integer :: test_array2(10,2)
  test_array1 = (/1, 2, 3, 4, 5, 6, 7, 8, 9, 10/)
  test_array2(:,1) = (/1,   2,  3,  4,  5,  6,  7,  8,  9, 10/)
  test_array2(:,2) = (/11, 12, 13, 14, 15, 16, 17, 18, 19, 20/)
  write(*,*) "print_a(test_array1, 10)"
  call print_a(test_array1, 10)
  write(*,*) "print_a(test_array2, 10)"
  call print_a(test_array2, 10)
  write(*,*) "print_a(test_array2, 20)"
  call print_a(test_array2, 20)
  write(*,*) "print_a(test_array2(:,2), 10)"
  call print_a(test_array2(:,2), 10)
  write(*,*) "print_m(test_array1, 2,5)"
  call print_m(test_array1, 2, 5)

contains

  subroutine print_a(a, n)
    integer, intent(in) :: n
    integer, intent(in) :: a(n)
    integer :: i
    do i = 1, n
      write(*,*) a(i)
    end do
  end subroutine

  subroutine print_m(a, n, m)
    integer, intent(in) :: n
    integer, intent(in) :: m
    integer, intent(in) :: a(n,m)
    integer :: i, j
    do i = 1, n
      do j = 1, m
        write(*,*) a(i,j)
      end do
    end do
  end subroutine

end program test


There are two alternatives to do basically the same thing, one standard, one not.
The first one is known as assumed-size, and looks like this:
Here, a has rank one, and a size large enough to fit whatever is passed to the routine.
However, the routine does not actually know the size of a (size(a) is illegal in this context).
There certainly is nothing that ensures that the size of a is n, and the compiler has no way of perfoming any checks on the use of a.
In that sense, assumed-size is not very useful compared to explicit-shape,
except maybe in some rare instances where the array size can somehow be deduced from the data stored in the array,
so that the array size n does not have to be passed along.
Code: Select all
subroutine print_a(a, n)
  integer, intent(in) :: a(*)
  integer, intent(in) :: n
  integer :: i
  do i = 1, n
    write(*,*) a(i)
  end do
end subroutine


The second alternative is a non-standard trick that behaves identically to assumed-size,
but was used before the assumed-size feature was introduced to Fortran. It looks like this:

Code: Select all
subroutine print_a(a, n)
  integer, intent(in) :: a(1)
  integer, intent(in) :: n
  integer :: i
  do i = 1, n
    write(*,*) a(i)
  end do
end subroutine


n principle, this is also an example of array element sequence association.
In the subroutine, a is called with subscripts outside of the bounds of its declared size 1,
which is more or less guaranteed to work since the array is passed by reference.
Again, the compiler has not idea about the actual size of a.
Most compilers will recognize this trick and not complain about going out of bounds, even with bound-checking enabled, \
understanding a(1) to be identical to a(*), with the only difference being that size(a) is legal, but of course returns 1,
i.e. not the size of the actual passed array. Declaring a as a(2) will not work, however.

Any of these definitions should only be used if the rank of the array needs to be changed.
For just passing arrays of identical rank, but unknown shape, one should always use the assumed-shape syntax (e.g. a(:,:))

A few pointers about where to find the discussed concepts in the Fortran 90 Handbook:
array element order is discussed in section 6.4.7, the definition of array element sequence association appears in section 12.5.2.1,
and explicit-shape, assumed-shape, deferred-shape, and assumed-size specification are explained in section 5.3.1.

Thanks to the people on comp.lang.fortran for illuminating some of these concepts to me.
thomas
 
Posts: 426
Joined: 2013年 May 4日, 09:52

Return to Programming Language

Who is online

Users browsing this forum: No registered users and 1 guest

cron