Fortran意图(inout)与省略意图

Fortran意图(inout)与省略意图,fortran,fortran90,Fortran,Fortran90,良好实践要求Fortran中的子例程参数都应具有指定的意图(如所述的intent(in)、intent(out)或intent(inout)): 但是,不指定意图是有效的Fortran: subroutine bar (a, b) real, intent(in) :: a real :: b b = b + a ... 除了编译时检查指定为intent(inout)的参数和没有指定意图的参数之外,还有什么真正的区别吗?如果我将意图改装为更旧、无意图的代码,有什

良好实践要求Fortran中的子例程参数都应具有指定的意图(如所述的
intent(in)
intent(out)
intent(inout)
):

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

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

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

您的问题让我想知道(现在有很多事情要做),如果您的代码将一个参数作为实际参数传递,然后您的子程序尝试写入该参数,您是否会遇到行为上的差异。如果没有意图声明,编译器可能会放弃这一点,导致奇怪的行为。对于该声明,我预期会出现编译时错误

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


快速阅读2003标准确实表明INOUT和NoIntent之间存在差异,但需要更仔细地阅读。如果你做了测试,让我们知道你的结论;如果我以后有时间,我会亲自测试并告诉你。

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


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

要理解intent in/out的作用,您需要知道Fortran在内部通过引用有效地传递变量。这并不总是与实际通过引用传递相同

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

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


它不仅起到了故障保护的作用,可以修改希望保持不变的数据,还可以在处理大型数据集时加快代码的速度。

我构建了四个测试用例,试图修改子例程中的参数。两个带有外部子例程的测试-即在一个文件中单独进行-有和没有意图(inout)。编译器不会对其中任何一个进行抱怨。这并不奇怪(没有接口)以及由此产生的错误。在最后两个测试中,我将子例程卡在一个模块中,并在接口中看到无意图情况下的segfault和编译器错误(“在(1)处的实际参数必须定义为伪参数'b'是intent=OUT/INOUT”)。这是来自debian系统的gfortran 4.4.4-2。现在,参数被放在内存的只读标记部分,但这并不总是正确的。在非常古老的编译器中,一个著名的例子是重新定义数值常量!您是否愿意/能够使用示例子程序解释差异?
subroutine bar (a, b)
    real, intent(in) :: a
    real :: b
    b = b + a
    ...