将字符/字符串从R传递到Fortran

3

我有一个Fortran子程序,它根据字符串的值选择一个函数,然后执行该函数。

!! file:select.f90
module funcs
    contains
        subroutine add(x, y, xy)
            real :: x, y, xy
            xy = x + y
            return
        end subroutine

        subroutine diff(x, y, xy)
            real :: x, y, xy
            xy = x - y
            return
        end subroutine
end module

subroutine simple(modname)
    use funcs

    procedure(), pointer :: model => null()

    character(10) :: modname
    real :: x, y, xy

    print *, "-",modname,"-"
    select case (modname)
        case("add")
            model => add
        case("diff")
            model => diff
        case default
            print *, "No model with that name!"
            stop
    end select

    x = 4
    y = 3
    call model(x, y, xy)
    print *, xy

end subroutine

我想从R脚本中调用这个子程序。
# file:select.R
dyn.load("select.so")
.Fortran("simple", "add")
.Fortran("simple", "diff")

作为一个独立的Fortran 程序,它可以很好地运行,并且对于modname前后的空格不敏感。但是,当我尝试从R中传入字符作为参数时,它会正确地重新打印字符(没有任何额外的空格),但随后无法将其识别为case并跳转到default。这是怎么回事?R字符是否存在某种编码问题,使其与Fortran不兼容?

谢谢您的建议!我尝试了,但没有成功。它可以编译和运行,因此该语句在语法上没有问题,但它并不能解决潜在的问题。编辑:原始评论已被删除,但建议是使用select case (adjustl(trim(modname))) - Alexey Shiklomanov
3
根据这个页面 http://www.nag.co.uk/numeric/RunderWindows.asp 的说法,当 .Fortran() 调用的 Fortran 程序包含字符参数时,它的行为是与系统相关的。因此,建议通过修改包装程序中的输入变量来避免使用字符类型。因此,使用整数等类型可能更好,以避免使用字符。 - roygvib
@roygvib 不错的发现,谢谢!我会保持这个问题的开放,以防有人能够提供更多的见解和/或解决方法,但暂时我将转而使用整数代码。 - Alexey Shiklomanov
@HighPerformanceMark:我不这么认为。 - Alex A.
1
如果 modname 可以成功打印,则可能的解决方法是仅比较子字符串,例如,if (modname(1:3)==“add”)then model => add endif,等等。因为这可能有助于避免字符编码问题(包括来自 R 端的空终止符)的潜在问题。 - roygvib
2
与@roygvib所说的类似,我在“编写R扩展”中找到了这个相关段落。将字符串传递给FORTRAN代码需要更多的注意,并且应该在可能的情况下避免使用。只有字符向量的第一个元素被传递,作为固定长度(255)的字符数组。最多可以传递255个字符回到长度为一的字符向量中。这是否有效(甚至是否起作用)取决于每个平台上的C和FORTRAN编译器(包括它们的选项)。 - Alexey Shiklomanov
1个回答

2
我认为你的选择语句没有正确匹配,因为modname有10个字符长,而你的所有情况都覆盖不了这样一个长度的字符串。最好的做法是在Fortran函数中也传入字符串的长度,然后使用它来切分字符数组。
例如:subroutine simple(modname, length) 接下来使用select case (modname(1:length)) Fortran字符串不像C语言一样以零结尾,它是基于数组的语言。
此外,在从R传递字符串到.Fortran时,最好将其作为原始字节传递。下面是一个简单的示例。首先是Fortran代码,然后是R包装器代码。
subroutine print_this ( str, length )
 integer :: length
 character(length) :: str
 print *, str(1:length)
end subroutine print_this 

test <- function(str) {
  l <- nchar(str) 
  str_raw <- character(l)
  str_raw <- charToRaw(str)
  .Fortran("print_this",str_raw,l)
  l #returns length
}

请注意,case("add")将匹配长度为10个字符的值"add "(这是带有七个尾随空格的 - 并非所有呈现)。被比较的字符值是短的被视为用空格填充到较长的长度。 - francescalus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接