Код 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