【问题标题】:Passing a value for an optional fortran parameter that will return false for present()传递一个可选的 fortran 参数的值,该参数将为 present() 返回 false
【发布时间】:2017-09-07 03:50:32
【问题描述】:

我想找到一种方法让 fortran 方法为可选参数获取一些值,这将使参数看起来不存在于已调用的方法中。

这是一个简化的测试用例,它在 fortran 代码中提炼出问题:

MODULE FortranOptional
  USE ISO_C_BINDING

CONTAINS
  SUBROUTINE optionaltest(scalar)
    REAL(8), OPTIONAL, INTENT(IN) :: scalar

    IF (PRESENT(scalar)) THEN
      print *, "scalar is present: ", scalar
    ELSE
      print *, "scalar is NOT present"
    END IF

  END SUBROUTINE optionaltest

  SUBROUTINE optionaltest_c(scalarC) BIND(C, NAME="optionaltest_c")
    REAL(C_DOUBLE), OPTIONAL, INTENT(IN) :: scalarC
    REAL(8) :: scalar

    IF (PRESENT(scalarC)) THEN
      print *, "scalarC is present: ", scalarC
      scalar = scalarC
    ELSE
      print *, "scalarC is NOT present"
      ! Can I do something here to make scalar appear not present in optionaltest()?
    END IF

    CALL optionaltest(scalar)
  END SUBROUTINE optionaltest_c
END MODULE FortranOptional

以及相关的C++测试代码:

extern "C"
{
void optionaltest_c(double*);
}

void testMethod()
{
    double v = 5.3;
    optionaltest_c(0);

    std::cout << "\n";

    optionaltest_c(&v);
}

产生:

scalarC is NOT present
scalar is present:    6.9118029901527309E-310

scalarC is present:    5.2999999999999998     
scalar is present:    5.2999999999999998     

有什么方法可以根据scalarC 的存在来设置scalar 变量,当scalarC 不存在时它看起来不存在?

一些限制:

  • 我宁愿避免 if 语句涉及对 optionaltest 的不同调用,因为子例程的实际版本有几个可选参数,这些参数可以单独指定或不指定,从而导致组合爆炸。

  • 我无法将 optionaltest 子例程直接绑定为 C 函数,因为子例程的实际版本采用了 shape 可选参数,而在我使用的 Fortran 版本中这些参数与 C 不兼容。

  • 我无法修改optionaltest的签名。

【问题讨论】:

  • @francescalus:不幸的是,在实际方法中,必须在转换步骤中进行计算,因此没有直接类似的变量可以简单地传递。
  • 也许我可以更好地解释一下:CALL optionaltest(scalar) 在子程序 optionaltest_c 中是否可能,或者您是否(可能是因为不同的种类/类型)有 scalarscalarC 不同的变量?
  • CALL optionaltest(scalar) 确实出现在optionaltest_c中;你的意思是CALL optionaltest(scalarC)?我不能做后者,因为正如你猜到的那样,标量和标量C 并不完全相同,我不能只通过 scalarC
  • 是的,我确实是指scalarC。出于兴趣(或最佳答案),您能说明编译器和版本吗?正如您所指出的,我们处于可变支持领域。
  • 我用的是gfortran 4.4.7,需要写Fortran90规范。

标签: fortran optional-parameters


【解决方案1】:

在子程序optionaltest_c 中,变量scalar 是一个局部变量。正如您所注意到的,局部变量没有可选性的概念。

为了完整起见,如果只是将可选的虚拟参数从optionaltest_c 传递到optionaltest,那么

call optionaltest(scalarC)

就够了。也就是说,一个可选的虚拟参数可能是一个过程的实际参数,其中相应的虚拟参数也是可选的,不管它是否存在。

那么,如果您需要进行某种形式的操作,该怎么办?1 我注意到您在虚拟参数和局部变量之间存在内在赋值。

在 Fortran 2008 下有一个明智的选择:让局部变量可分配。如果变量未分配并且是可选的不可分配虚拟变量的实际参数,则将其视为不存在:

  subroutine optionaltest_c(scalarC) bind(C)
    type(type1), optional, intent(in) :: scalarC
    type(type2), allocatable :: scalar  ! Local, conformable with scalarC

    if (PRESENT(scalarC)) scalar=scalarC
    ...

    call optionaltest(scalar)
  end subroutine optionaltest_c

[您可能需要提供分配scalar 并设置其值的替代方法,具体取决于您的编译器支持。]

scalarC 存在时,scalar 被分配并具有其值。然后在调用时,存在虚拟参数。由于scalarC 不存在,scalar 未被分配,并且在调用时虚拟参数不存在。

这对于数组和标量同样适用。

现在,我看到您提到了 gfortran 4.4.7,因此这种方法可能行不通。在这种情况下,我会让其他人以特定方式回答,但这也许仍然值得为他人的利益/升级后记录。


1如果c_double 的值为8,则可能不是这个问题的情况,但我们还是会考虑。

【讨论】:

  • 制作allocatable 是我所需要的;我不知道可以为标量变量做这件事。谢谢。
  • 可分配标量(在 F2003 中引入),即使是内在类型,也是非常有用的生物。
  • 我们可以将未分配的可分配变量传递给可选的虚拟参数吗?这可能会简化我的代码中的很多地方。非关联指针也一样?
  • (距离我意识到我可以将一个可选的 dummy 作为可选的实际参数传递仅两年时间,第 188 行 bitbucket.org/LadaF/elmm/commits/…
  • @VladimirF,对未分配的可分配和解除关联的指针都是肯定的,只要虚拟不是可分配的(第一个)或指针(第二个)。参见 F2008 12.5.2.12。这是 F2008 的新手(非常欢迎我),我不知道在 gfortran 中的支持。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-09
  • 2021-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多