Код Fortran 77 с несовместимыми вызывающими последовательностями - как модулировать в Fortran 90/95?

Рассмотрим следующий унаследованный "реальный мир" код Fortran 77, который в соответствии со стандартом вполне может быть недопустимым, но работает в реальной жизни с широким спектром компиляторов и не выдает предупреждений компилятора или компоновщика, если каждая подпрограмма компилируется отдельно.

subroutine a
complex z(10)
call b(z)
call r1(z)
call r2(z)
end

subroutine b(z)
complex z(10)
c ... use complex arithmetic on z
end

subroutine r1(x)
real x(2,10)
c ... do something with real and imaginary parts
c ... real parts are x(1,*)
c ... imaginary parts are x(2,*)
end

subroutine r2(x)
real x(20)
c ... do something with real and imaginary parts
end

Я хочу повторно упаковать код в этом стиле, используя модули Fortran 90/95. Наивный подход

module m
public a
private b, r1, r2
contains 

subroutine a
complex z(10)
call b(z)
call r1(z)
call r2(z) 
end subroutine a

subroutine b(z)
complex z(10)
c ... use complex arithmetic on z
end subroutine b

subroutine r1(x)
real x(2,10)
c ... do something with real and imaginary parts
c ... real parts are x(1,*)
c ... imaginary parts are x(2,*)
end subroutine r1

subroutine r2(x)
real x(20)
c ... do something with real and imaginary parts
end subroutine r2

end module m

не компилируется, потому что (конечно) компилятор теперь может видеть, что подпрограммы r1 и r2 вызываются с неверным типом аргумента.

Мне нужны некоторые идеи о том, как это исправить, с минимальным переписыванием существующего кода и без создания дублирующих копий данных в памяти - реальный размер данных слишком велик для этого.

3 ответа

Решение

c_f_pointer() может быть полезен для получения real(2,*) указатель на complex(*) массив, но я не уверен, что передача комплексного параметра (zconst(:)) в ctor () действительно хорошо... (здесь я использовал gfortran 4.4 и 4.8 и ifort 14.0, и чтобы сделать вывод более компактным массивом) размерность изменена с 10 на 3.)

module m
    implicit none
contains

subroutine r1 ( x )
    real x( 2, 3 )

    print *
    print *, "In r1:"
    print *, "Real part = ",x( 1, : )
    print *, "Imag part = ",x( 2, : )
endsubroutine

subroutine r2 ( x )
    real x( 6 )

    print *
    print *, "In r2:"
    print *, "all elements = ", x( : )
endsubroutine

subroutine b ( z )
    complex :: z( 3 )
    real, pointer :: rp(:,:)

    rp => ctor( z, 3 )  !! to compare z and rp                                      
    print *
    print *, "In b:"
    print *, "1st elem = ", z( 1 ), rp( :, 1 )
    print *, "3rd elem = ", z( 3 ), rp( :, 3 )
endsubroutine

function ctor( z, n ) result( ret )   !! get real(2,*) pointer to complex(*)
    use iso_c_binding
    implicit none
    integer :: n
    complex, target :: z( n )
    real, pointer :: ret(:,:)
    call c_f_pointer( c_loc(z(1)), ret, shape=[2,n] )
endfunction

endmodule

program main
    use m
    implicit none
    complex z(3)
    complex, parameter :: zconst(3) = [(7.0,-7.0),(8.0,-8.0),(9.0,-9.0)]

    z(1) = ( 1.0, -1.0 )
    z(2) = ( 2.0, -2.0 )
    z(3) = ( 3.0, -3.0 )

    call r1 ( ctor( z, 3 ) )
    call r1 ( ctor( zconst, 3 ) )

    call r2 ( ctor( z, 3 ) )
    call r2 ( ctor( zconst, 3 ) )

    call b ( z )
    call b ( zconst )
 endprogram

(Возможно, это скорее комментарий, чем ответ, но вы не можете включить отформатированный код в комментарий).

@roygvib ответил на вопрос в стандартном Fortran 2003.

Эту же идею можно сформулировать более кратко, используя нестандартный синтаксис "Cray Fortran pointer", который реализован во многих компиляторах - например, -fcray-pointer вариант в гфортране. Нестандартная встроенная функция loc заменяет ctor,

subroutine b ( z )
    complex :: z( 3 )

    real :: r( 2, 3 )
    pointer(zp, r)
    zp = loc(z)

    print *
    print *, "In b:"
    print *, "1st elem = ", z( 1 ), r( :, 1)
    print *, "3rd elem = ", z( 3 ), r( :, 3)
endsubroutine

Обратите внимание, что следующее предложение имеет некоторые регрессивные аспекты.

В примере кода в вопросе исходным источником данных является локальная переменная. Такая локальная переменная может появляться в контексте ассоциации хранения с использованием оператора эквивалентности, и в таком контексте можно рассматривать объект COMPLEX как пару объектов REAL.

module m
  public a
  private b, r1, r2
contains 
  subroutine a
    complex z(10)
    real r(size(z)*2)
    equivalence (z,r)
    call b(z)     ! pass complex array
    call r1(r)    ! pass real array
    call r2(r)    ! pass real  array
  end subroutine a

  subroutine b(z)
    complex z(10)
    ! ... use complex arithmetic on z
  end subroutine b

  subroutine r1(x)
    real x(2,10)
    ! ... do something with real and imaginary parts
    ! ... real parts are x(1,*)
    ! ... imaginary parts are x(2,*)
  end subroutine r1

  subroutine r2(x)
    real x(20)
    ! ... do something with real and imaginary parts
  end subroutine r2
end module m
Другие вопросы по тегам