Fortran 意图(inout)与省略意图
良好的实践表明,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)
的参数和没有指定意图的参数之外,是否还有任何真正的区别?如果我将意图改造为旧的、无意图的代码,我应该担心什么吗?
Good practice dictates that subroutine arguments in Fortran should each have a specified intent (i.e. intent(in)
, intent(out)
or intent(inout)
as described this question):
subroutine bar (a, b)
real, intent(in) :: a
real, intent(inout) :: b
b = b + a
...
However, not specifying an intent is valid Fortran:
subroutine bar (a, b)
real, intent(in) :: a
real :: b
b = b + a
...
Are there any real differences beyond compile time checking for an argument specified as intent(inout)
and an argument without a specified intent? Is there anything I should worry about if I'm retrofitting intents to older, intent free, code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
根据 Adams 等人的 The Fortran 2003 Handbook,intent(inout) 参数和没有指定意图的参数之间存在一个区别。 Intent(inout) 情况下的实际参数(即,在调用者中)必须始终是可定义的。如果未指定意图,则如果子例程的执行尝试定义虚拟参数,则该参数必须是可定义的。 可定义表示设置值:dummy_arg = 2.0。显然,如果这样做的话,实际参数应该是一个变量。对于intent(inout),无论子例程是否执行此操作,实际参数都必须是可定义的。如果没有指定意图,它取决于子例程的特定调用时发生的情况 - 如果子例程没有定义变量,则可以;如果确实如此,那么就会出现问题——诸如写入常量的实际参数之类的情况显然会导致问题。
这并不意味着编译器将诊断所有这些情况 - 标准要求编译器诊断的是不同的问题。在编译时检测未指定意图的情况要求的所有错误几乎是不可能的,因为违规取决于代码的运行时流程。编译器更容易诊断意图(inout)情况并警告您代码存在问题。
According to The Fortran 2003 Handbook by Adams, et al., there is one difference between an intent(inout) argument and argument without specified intent. The actual argument (i.e., in the caller) in the intent(inout) case must always be definable. If the intent is not specified, the argument must be definable if execution of the subroutine attempts to define the dummy argument. definable means setting the value: dummy_arg = 2.0. Clearly the actual argument should be a variable if this is done. For intent(inout) the actual argument must be definable whether or not the subroutine does this. Without no intent specified, it depends on what happens on that particular invocation of the subroutine -- if the subroutine doesn't define the variable, it is OK; if it does, than there is a problem -- cases such as writing to an actual argument that is a constant will obviously cause problems.
This doesn't mean that the compiler will diagnose all of these cases -- what the standard requires a compiler to diagnose is a different issue. It would be close to impossible to detect all errors of the intent-not-specified case requirement at compile time, since violations depend on the run-time flow of the code. It is much easier for the compiler to diagnose the intent(inout) case and warn you of problems with the code.
您的问题促使我想知道(现在有很多事情要做)如果您的代码将 PARAMETER 作为实际参数传递给子程序然后尝试写入,您是否可能会遇到行为差异。如果没有 INTENT 声明,编译器可能会放弃此操作,从而导致奇怪的行为。通过声明,我预计会出现编译时错误。
你和我可能认为 INOUT 和没有 INTENT 声明之间没有区别,但不要忘记有很多旧的 Fortran 程序,并且与旧语言版本的兼容性是新标准的一个重要特性。如果 FORTRAN77 是正确的(但不可靠),那么很多人希望他们的代码在 Fortran 90+ 编译器中保持正确(仍然不可靠)。
快速阅读 2003 年标准确实表明 INOUT 和无 INTENT 之间存在差异,但需要更仔细地阅读。如果您确实进行了测试,请告诉我们您的结论;如果以后有时间我会亲自测试一下并告诉你。
Your question prompts me to wonder (lots to do right now) whether you might encounter a difference in behaviour if your code passes a PARAMETER as an actual argument which your sub-program then attempts to write to. Without an INTENT declaration the compiler might let this go, leading to odd behaviour. With the declaration I'd expect a compile-time error.
You and I might think that there is no difference between INOUT and no INTENT declaration, but don't forget that there are a lot of old Fortran programs out there and that compatibility with older language versions is an important feature of new standards. If it was correct (but dodgy) FORTRAN77 then a lot of people expect their code to remain correct (still dodgy) with a Fortran 90+ compiler.
A quick read of the 2003 standard does indicate that there is a difference between INOUT and no INTENT, but more close reading is required. If you do test this let us know your conclusions; if I have time later I will test it myself and let you know.
要理解意图输入/输出的作用,您需要知道 Fortran 在内部有效通过引用传递变量。这并不总是与实际通过引用传递相同。
如果将二维数组的内部子部分传递给子例程,即:
data(i1:i2, j1:j2)
,则 Fortran 会将该数据复制到内存的连续部分,并传递例程的新地址。返回后,数据将被复制回其原始位置。通过指定
INTENT
,编译器可以知道跳过其中一个复制操作。它不仅可以作为修改您希望保持不变的数据的故障保护,而且还可以在处理大型数据集时加快您的代码速度。
To understand the role of intent in/out, you need to know that internally, Fortran effectively passes variables by reference. This isn't always the same as actually passing by reference.
If you pass an internal subsection of an 2-D array to a subroutine, ie:
data(i1:i2, j1:j2)
, then Fortran copies that data into a contiguous section of memory, and passes the new address to the routine. Upon returning, the data is copied back into its original location.By specifying
INTENT
, the compiler can know to skip one of the copying operations.It not only acts as a failsafe for modifying data that you want to remain unchanged, but also can speed up your code when dealing with large datasets.
为了以某种方式扩展 MSB 的答案,省略
intent
可以为您提供更大的灵活性,但代价是减少编译时检查。如果没有intent
,如果您知道代码分支不会尝试修改它,则可以传递文字常量,如果您使用intent(inout)
,编译器可能会向您咆哮尝试一下。这对于“双重”过程可能很有用,该过程将根据选项修改或不修改某些参数,例如:如果您想将
intent
添加到x
和a
,两者都必须是inout
,因为两者都可能被读取和修改。但这不允许您编写例如这个示例非常愚蠢,但请考虑一个更复杂的子例程,它可以读取或写入具有某些复杂格式的文件。 (我并不是说这是最好的解决方案,但您可以轻松找到它。)
To somehow expand M.S.B.'s answer, omitting
intent
gives you more flexibility, at the cost of less compile-time checking. Withoutintent
, you can pass a literal constant if you know the code branch will not attempt to modify it, withintent(inout)
the compiler will probably bark at you if you try it. This may be useful with "dual" procedures that will modify or not some argument depending on the options, for example:If you want to add
intent
tox
anda
, it must beinout
for both, because both are potentially read and modified. But that will not allow you to write e.g.This example is quite silly, but think of a more elaborate subroutine that can read from or write to a file with some complex formatting. (I'm not saying that's the best solution, but it's something you can easily find.)