36

良好实践规定 Fortran 中的子例程参数每个都应具有指定的意图(即intent(in)intent(out)intent(inout)本问题所述):

subroutine bar (a, b)
    real, intent(in) :: a
    real, intent(inout) :: b
    b = b + a
    ...

但是,不指定意图是有效的 Fortran:

subroutine bar (a, b)
    real, intent(in) :: a
    real :: b
    b = b + a
    ...

除了编译时检查指定为intent(inout)的参数和没有指定意图的参数之外,是否有任何真正的区别?如果我将意图改造为旧的、无意图的代码,我应该担心什么?

4

4 回答 4

26

根据Adams 等人的 Fortran 2003 手册,intent(inout) 参数和没有指定意图的参数之间存在一个区别。Intent(inout) 情况下的实际参数(即在调用者中)必须始终是可定义的。如果未指定意图,则如果子例程的执行尝试定义虚拟参数,则该参数必须是可定义的。 可定义的表示设置值:dummy_arg = 2.0。显然,如果这样做,实际参数应该是一个变量。对于意图(输入输出),无论子例程是否执行此操作,实际参数都必须是可定义的。如果没有指定意图,它取决于子例程的特定调用发生了什么——如果子例程没有定义变量,那没关系;如果是这样,那就有问题了——比如写入一个常量的实际参数显然会导致问题。

这并不意味着编译器会诊断所有这些情况——标准要求编译器诊断的是一个不同的问题。在编译时检测意图未指定案例要求的所有错误几乎是不可能的,因为违规取决于代码的运行时流程。编译器更容易诊断意图(输入)情况并警告您代码问题。

于 2010-05-21T14:38:28.230 回答
7

您的问题让我想知道(现在有很多事情要做)如果您的代码将 PARAMETER 作为实际参数传递给您的子程序然后尝试写入,您是否会遇到行为差异。如果没有 INTENT 声明,编译器可能会放手,导致奇怪的行为。通过声明,我预计会出现编译时错误。

你和我可能认为 INOUT 和没有 INTENT 声明之间没有区别,但不要忘记那里有很多旧的 Fortran 程序,并且与旧语言版本的兼容性是新标准的一个重要特征。如果它是正确的(但狡猾的)FORTRAN77,那么很多人希望他们的代码使用 Fortran 90+ 编译器保持正确(仍然狡猾)。

快速阅读 2003 标准确实表明 INOUT 和无 INTENT 之间存在差异,但需要更仔细地阅读。如果您对此进行测试,请告诉我们您的结论;如果我以后有时间我会自己测试并让你知道。

于 2010-05-21T09:03:06.677 回答
4

要了解意图输入/输出的作用,您需要知道在内部,Fortran通过引用有效地传递变量。这并不总是与实际通过引用传递相同。

如果将二维数组的内部子部分传递给子例程,即:data(i1:i2, j1:j2),则 Fortran 将该数据复制到内存的连续部分中,并将新地址传递给例程。返回后,数据将被复制回其原始位置。

通过指定INTENT,编译器可以知道跳过其中一个复制操作。

它不仅可以作为修改您希望保持不变的数据的故障保险,而且可以在处理大型数据集时加速您的代码。

于 2016-04-14T21:40:53.427 回答
0

为了以某种方式扩展 MSB 的答案,省略intent为您提供了更大的灵活性,但代价是编译时检查更少。如果没有intent,如果您知道代码分支不会尝试修改它,您可以传递一个文字常量,如果您尝试它,intent(inout)编译器可能会向您咆哮。这对于将根据选项修改或不修改某些参数的“双重”过程可能很有用,例如:

subroutine copy(x,a,readwrite)
integer :: x, a
integer, intent(in) :: readwrite

if (readwrite == 0) then
  x = a
else
  a = x
end if

end subroutine

如果要添加intentxand a,则必须同时inout用于两者,因为两者都可能被读取和修改。但这不会让你写例如

call copy(x,3,0)  ! equiv. to x=3
call copy(42,a,1) ! equiv. to a=42

这个例子很傻,但是想想一个更复杂的子程序,它可以读取或写入具有一些复杂格式的文件。(我并不是说这是最好的解决方案,但它是您可以轻松找到的。)

于 2021-09-29T09:43:19.537 回答