具有不兼容调用序列的 Fortran 77 代码 - 如何在 Fortran 90/95 中模块化?
Fortran 77 code with incompatible calling sequences - how to modularize in Fortran 90/95?
考虑以下 "real world" 遗留 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 是用错误的参数类型调用的。
我需要一些关于如何解决这个问题的想法,以最少的现有代码重写量,并且无需在内存中复制数据 - 真正的-数据的真实大小对于那个来说太大了。
请注意以下建议有一些倒退的方面。
问题中的示例代码中,数据的原始来源是局部变量。这样的局部变量可以通过使用等价语句出现在存储关联上下文中,并且在这样的上下文中可以将 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
c_f_pointer() 可能有助于获取指向 complex(*)
数组的 real(2,*)
指针,但我不确定是否将复杂参数 (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" 语法更简洁地编码 - 例如 gfortran 中的 -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
考虑以下 "real world" 遗留 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 是用错误的参数类型调用的。
我需要一些关于如何解决这个问题的想法,以最少的现有代码重写量,并且无需在内存中复制数据 - 真正的-数据的真实大小对于那个来说太大了。
请注意以下建议有一些倒退的方面。
问题中的示例代码中,数据的原始来源是局部变量。这样的局部变量可以通过使用等价语句出现在存储关联上下文中,并且在这样的上下文中可以将 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
c_f_pointer() 可能有助于获取指向 complex(*)
数组的 real(2,*)
指针,但我不确定是否将复杂参数 (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" 语法更简洁地编码 - 例如 gfortran 中的 -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