R 使用字符参数调用 Fortran 子例程
R calling Fortran subroutine with character argument
如何从 R 中调用带有字符参数的 Fortran 子例程?尽管我能够使用双精度参数调用 Fortran 子例程,但我这样做的尝试并没有奏效。对于 Fortran 代码
subroutine square(x,x2)
double precision, intent(in) :: x
double precision, intent(out) :: x2
x2 = x*x
end subroutine square
subroutine pow(c,x,y)
character (len=255), intent(in) :: c
double precision, intent(in) :: x
double precision, intent(out) :: y
if (c == "s") then
y = x**2
else if (c == "c") then
y = x**3
else
y = -999.0d0 ! signals bad argument
end if
end subroutine pow
和R代码
dyn.load("power.dll") # dll created with gfortran -shared -fPIC -o power.dll power.f90
x <- 3.0
foo <- .C("square_",as.double(x),as.double(0.0))
print(foo)
bar <- .C("pow_",as.character("c"),as.double(x),as.double(0.0))
print(bar)
来自
的输出
C:\programs\R\R-3.6.1\bin\x64\rterm.exe --vanilla --slave < xcall_power.r
是
[[1]]
[1] 3
[[2]]
[1] 9
[[1]]
[1] "c"
[[2]]
[1] 3
[[3]]
[1] -999
当您使用 .C
调用 Fortran 子例程时,调用会将字符参数视为 C 风格 char **
。这与 character(len=255)
.
类型的 Fortran 虚拟参数不兼容
您有两种 'simple' 方法可用:
- 修改 Fortran 子例程以接受类似于
char **
的参数
- 使用
.Fortran
代替.C
修改 Fortran 子例程以使用 C 与 char **
的互操作性是一个新问题的主题(因为它的广度并且不特定于您的 R 问题)。一般来说,我更喜欢编写用于 R 的 Fortran 过程,因为它公开了 C 可互操作的接口和 .C
或 .Call
。通过下面的内容,您可能也会得出这样的结论。
即使是 R 文档也不乐观地使用 .Fortran
:
传递字符参数
‘.Fortran’ passes the first (only) character string of a character vector as a C character array to Fortran: that may be usable as ‘character*255’ if its true length is passed separately. Only up to 255 characters of the string are passed back. (How well this works, and even if it works at all, depends on the C and Fortran compilers and the platform.)
您需要阅读有关参数传递约定的文档,例如 for gfortran(这些约定可能会更改,请查阅相应的版本)。
使用 .Fortran
和 gfortran 然后使用不可与 C 互操作的过程,您将需要将 "hidden" 参数传递给指定字符参数长度的 Fortran 过程。对于显式长度字符(恒定长度,甚至长度为 1 或不是)和假定长度字符都是如此。
对于版本7之前的gfortran,这个隐藏参数是(R)类型整数。使用问题的 pow
或假设长度参数,我们可以尝试类似
bar <- .Fortran("pow", as.character("c"), as.double(x), as.double(0.0), 255L)
但是请注意,这不是标准的并且本质上不可移植。事实上,正如 janneb 评论和上面链接的文档所述,如何将这个隐藏参数从 R 传递到 gfortran 编译过程取决于 version of gfortran used。在最后使用 255L
可能不会超出 gfortran 7。相反,您需要将隐藏参数作为匹配 integer(c_size_t)
(可能是 64 位整数)的东西传递。对于 gfortran 以外的编译器,您可能需要做一些完全不同的事情。
最好使用 C 互操作过程,其参数可与 char **
(使用 .C
)或 char []
(使用 .Fortran
)互操作。正如我所说,这里值得选择第一个选项,因为它具有更大的灵活性(例如更长的字符、更多的可移植性和更多的字符参数)。
如何从 R 中调用带有字符参数的 Fortran 子例程?尽管我能够使用双精度参数调用 Fortran 子例程,但我这样做的尝试并没有奏效。对于 Fortran 代码
subroutine square(x,x2)
double precision, intent(in) :: x
double precision, intent(out) :: x2
x2 = x*x
end subroutine square
subroutine pow(c,x,y)
character (len=255), intent(in) :: c
double precision, intent(in) :: x
double precision, intent(out) :: y
if (c == "s") then
y = x**2
else if (c == "c") then
y = x**3
else
y = -999.0d0 ! signals bad argument
end if
end subroutine pow
和R代码
dyn.load("power.dll") # dll created with gfortran -shared -fPIC -o power.dll power.f90
x <- 3.0
foo <- .C("square_",as.double(x),as.double(0.0))
print(foo)
bar <- .C("pow_",as.character("c"),as.double(x),as.double(0.0))
print(bar)
来自
的输出C:\programs\R\R-3.6.1\bin\x64\rterm.exe --vanilla --slave < xcall_power.r
是
[[1]]
[1] 3
[[2]]
[1] 9
[[1]]
[1] "c"
[[2]]
[1] 3
[[3]]
[1] -999
当您使用 .C
调用 Fortran 子例程时,调用会将字符参数视为 C 风格 char **
。这与 character(len=255)
.
您有两种 'simple' 方法可用:
- 修改 Fortran 子例程以接受类似于
char **
的参数
- 使用
.Fortran
代替.C
修改 Fortran 子例程以使用 C 与 char **
的互操作性是一个新问题的主题(因为它的广度并且不特定于您的 R 问题)。一般来说,我更喜欢编写用于 R 的 Fortran 过程,因为它公开了 C 可互操作的接口和 .C
或 .Call
。通过下面的内容,您可能也会得出这样的结论。
即使是 R 文档也不乐观地使用 .Fortran
:
‘.Fortran’ passes the first (only) character string of a character vector as a C character array to Fortran: that may be usable as ‘character*255’ if its true length is passed separately. Only up to 255 characters of the string are passed back. (How well this works, and even if it works at all, depends on the C and Fortran compilers and the platform.)
您需要阅读有关参数传递约定的文档,例如 for gfortran(这些约定可能会更改,请查阅相应的版本)。
使用 .Fortran
和 gfortran 然后使用不可与 C 互操作的过程,您将需要将 "hidden" 参数传递给指定字符参数长度的 Fortran 过程。对于显式长度字符(恒定长度,甚至长度为 1 或不是)和假定长度字符都是如此。
对于版本7之前的gfortran,这个隐藏参数是(R)类型整数。使用问题的 pow
或假设长度参数,我们可以尝试类似
bar <- .Fortran("pow", as.character("c"), as.double(x), as.double(0.0), 255L)
但是请注意,这不是标准的并且本质上不可移植。事实上,正如 janneb 评论和上面链接的文档所述,如何将这个隐藏参数从 R 传递到 gfortran 编译过程取决于 version of gfortran used。在最后使用 255L
可能不会超出 gfortran 7。相反,您需要将隐藏参数作为匹配 integer(c_size_t)
(可能是 64 位整数)的东西传递。对于 gfortran 以外的编译器,您可能需要做一些完全不同的事情。
最好使用 C 互操作过程,其参数可与 char **
(使用 .C
)或 char []
(使用 .Fortran
)互操作。正如我所说,这里值得选择第一个选项,因为它具有更大的灵活性(例如更长的字符、更多的可移植性和更多的字符参数)。