假设我有以下Fortran子例程:
subroutine f_test(n,x,value)
use iso_c_binding
implicit none
integer, intent(in) :: n
real(kind=8), intent(in) :: x(n)
real(kind=8), intent(out) :: value
integer(kind=c_int) :: n_
real(kind=c_double) :: value_,x_(n)
n_ = transfer( n, n_ )
x(1:n) = transfer( x(1:n), x_(1:n) )
call c_test(n_,x_,value_)
value = transfer( value_, value )
end subroutine f_test
并且还假设c_test
是指向C例程的指针,该例程对向量x
起作用并在value
变量中返回结果。
这很有效,但我有一个问题:
向量x
的转换会极大地影响调用子例程f_test
的算法的复杂性。我的意思是,如果这样的算法调用f_test
n
次,算法的复杂性将是二次的,但如果没有这种转换,它将只是线性的。因此,以这种方式进行的转换是不切实际的。有没有合理的方法来解决这个问题?
答案 0 :(得分:3)
Fortran内在transfer
不转换数字类型,它只是复制位,绕过类型。没有转换。如果integer
和integer (c_int)
应为不同类型,或real (kind=8)
和real (c_double)
种不同类型,则必须进行转换,但转移不会进行转换。赋值语句或内部函数(如int
或real
)可能会影响转换。
我假设您使用real (kind=8)
来表示8字节的实数。无法保证8的种类值对应于该类型。这已在Stackoverflow上多次讨论过,例如Fortran: integer*4 vs integer(4) vs integer(kind=4)
没有限定条件的integer
类型和integer (c_int)
可能相同,在这种情况下,无需转换。与其他类似...在这种情况下,编译器可能会接受call c_test(n,x,value)
,认识到类型是相同的,因为类型的数值是相同的,即使使用了不同的符号。为了更加可移植,您可以为输入参数设置int
和real
内部函数,并使用输出的赋值:
call c_test ( int (n, c_int), real (x, c_double), value_)
value = value_
如果您想确保不进行转换,可以在整个Fortran代码中使用integer (c_int)
,real (c_double)
等。这也可以为您提供一种指定8字节实数的可移植方式。 (也可以使用ISO_FORTRAN_ENV来完成。)
答案 1 :(得分:3)
为什么使用转帐?如果C例程可以直接使用x的内部表示,那么只需将其传递给x。如果您要从kind 8转换为kind c_double,那么只需使用赋值。
C例程是否修改x或n(它是否按值取值?)?假设没有,并假设转移的使用不是出于其他一些未说明的原因 - 在许多平台上,C_double的值是8,默认的整数种类是c_int的值。捷径是值得的。
if (kind(x) == c_double .and. kind(n) == c_int) then
call c_test(n, x, value)
else
n_ = n
x_ = x
call c_test(n_, x_, value_)
value = value_
end if